//// Copyright (c) 2019 Google Inc.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//#import "MainViewController.h"#import "NSDate+Format.h"#import "UITextView+Placeholder.h"@import Firebase;@import MaterialComponents;NS_ASSUME_NONNULL_BEGIN@interface UIView (Constraints)- (void)addConstraintsWithFormat:(NSString *)format views:(NSArray<UIView *> *)views;@end@implementation UIView (Constraints)- (void)addConstraintsWithFormat:(NSString *)format views:(NSArray<UIView *> *)views {NSMutableDictionary *viewsDictionary = [[NSMutableDictionary alloc] initWithCapacity:views.count];for (int i = 0; i < views.count; i++) {UIView *view = views[i];NSString *key = [NSString stringWithFormat:@"v%d", i];view.translatesAutoresizingMaskIntoConstraints = false;viewsDictionary[key] = view;}[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:formatoptions:0metrics:nilviews:viewsDictionary]];}@end@interface MainViewController ()@property(strong, nonatomic) NSMutableArray<FIRTextMessage *> *messages;@property(nonatomic) BOOL isLocalUser;@property(strong, nonatomic) NSLayoutConstraint *bottomConstraint;@property(strong, nonatomic) NSLayoutConstraint *heightConstraint;@property(strong, nonatomic) NSLayoutConstraint *inputBottomConstraint;@property(strong, nonatomic) NSLayoutConstraint *sendBottomConstraint;@property(nonatomic) BOOL isKeyboardShown;@property(strong, nonatomic) UIView *messageInputContainerView;@property(strong, nonatomic) FIRSmartReply *smartReply;@property(nonatomic) CGFloat bottomAreaInset;@property(strong, nonatomic) UITextView *inputTextView;@property(strong, nonatomic) UIStackView *smartReplyView;@property(strong, nonatomic) UILabel *updatedLabel;@property(strong, nonatomic) MDCFloatingButton *sendButton;@property(nonatomic, strong) UIAlertController *moreAlert;@end@implementation MainViewController- (UIAlertController *)moreAlert {if (_moreAlert == nil) {_moreAlert = [UIAlertController alertControllerWithTitle:nilmessage:nilpreferredStyle:UIAlertControllerStyleActionSheet];[_moreAlert addAction:[UIAlertAction actionWithTitle:@"Generate basic history"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *action) {[self generateChatHistoryBasic];}]];[_moreAlert addAction:[UIAlertAction actionWithTitle:@"Generate history with sensitive content"style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *action) {[self generateChatHistoryWithSensitiveContent];}]];[_moreAlert addAction:[UIAlertAction actionWithTitle:@"Clear chat history"style:UIAlertActionStyleDestructivehandler:^(UIAlertAction *action) {self.messages = [NSMutableArray new];[self updateReplies];[self.collectionView reloadData];}]];[_moreAlert addAction:[UIAlertAction actionWithTitle:@"Cancel"style:UIAlertActionStyleCancelhandler:nil]];}return _moreAlert;}- (void)viewDidLoad {[super viewDidLoad];self.messages = [NSMutableArray new];self.isLocalUser = YES;self.messageInputContainerView = [UIView new];_messageInputContainerView.backgroundColor = UIColor.whiteColor;self.smartReply = [[FIRNaturalLanguage naturalLanguage] smartReply];self.bottomAreaInset = 0;self.inputTextView = [[UITextView alloc] initWithPlaceholder:@"Write a message"];_inputTextView.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCallout];_inputTextView.scrollEnabled = NO;self.smartReplyView = [UIStackView new];_smartReplyView.distribution = UIStackViewDistributionEqualSpacing;for (int i = 0; i < 3; i++) {MDCChipView *chipView = [MDCChipView new];chipView.hidden = YES;[chipView setTitleColor:UIColor.redColor forState:UIControlStateSelected];NSLayoutConstraint *widthConstraint = [chipView.widthAnchor constraintEqualToConstant:0];widthConstraint.identifier = @"width";widthConstraint.active = YES;[chipView addTarget:selfaction:@selector(replySelected:)forControlEvents:UIControlEventTouchUpInside];[_smartReplyView addArrangedSubview:chipView];}self.sendButton = [[MDCFloatingButton alloc] initWithFrame:CGRectNullshape:MDCFloatingButtonShapeMini];[_sendButton setImage:[UIImage imageNamed:@"ic_send"] forState:UIControlStateNormal];_sendButton.tintColor = UIColor.blueColor;_sendButton.backgroundColor = UIColor.whiteColor;_sendButton.accessibilityLabel = @"Send";_sendButton.enabled = NO;[_sendButton addTarget:selfaction:@selector(enterPressed)forControlEvents:UIControlEventTouchUpInside];self.navigationController.navigationBar.barTintColor = UIColor.blueColor;[self.collectionView registerClass:MDCSelfSizingStereoCell.classforCellWithReuseIdentifier:@"cell"];if (@available(iOS 11, *)) {_bottomAreaInset = UIApplication.sharedApplication.keyWindow.safeAreaInsets.bottom;}self.isKeyboardShown = NO;_inputTextView.delegate = self;[NSNotificationCenter.defaultCenter addObserver:selfselector:@selector(handleKeyboardNotification:)name:UIKeyboardWillShowNotificationobject:nil];[NSNotificationCenter.defaultCenter addObserver:selfselector:@selector(handleKeyboardNotification:)name:UIKeyboardWillHideNotificationobject:nil];((UICollectionViewFlowLayout *)self.collectionViewLayout).estimatedItemSize =CGSizeMake(self.collectionView.bounds.size.width, 52);[self.view addSubview:_messageInputContainerView];[self.view addConstraintsWithFormat:@"H:|[v0]|" views:@[ _messageInputContainerView ]];self.heightConstraint =[_messageInputContainerView.heightAnchor constraintEqualToConstant:88 + _bottomAreaInset];self.bottomConstraint = [NSLayoutConstraint constraintWithItem:_messageInputContainerViewattribute:NSLayoutAttributeBottomrelatedBy:NSLayoutRelationEqualtoItem:self.viewattribute:NSLayoutAttributeBottommultiplier:1constant:0];[self.view addConstraint:_bottomConstraint];[self.view addConstraint:_heightConstraint];[self setupInputComponents];}- (void)setupInputComponents {UIView *topBorderView = [UIView new];topBorderView.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.5];[_messageInputContainerView addSubview:_inputTextView];[_messageInputContainerView addSubview:_sendButton];[_messageInputContainerView addSubview:topBorderView];[_messageInputContainerView addSubview:_smartReplyView];[_messageInputContainerView addConstraintsWithFormat:@"H:|-8-[v0][v1(40)]-16-|"views:@[ _inputTextView, _sendButton ]];[_messageInputContainerView addConstraintsWithFormat:@"H:|[v0]|" views:@[ topBorderView ]];[_messageInputContainerView addConstraintsWithFormat:@"H:|-16-[v0]-16-|" views:@[ _smartReplyView ]];[_smartReplyView.topAnchor constraintEqualToAnchor:_messageInputContainerView.topAnchorconstant:6].active = YES;[_smartReplyView.bottomAnchor constraintEqualToAnchor:_inputTextView.topAnchor constant:-6].active = YES;self.inputBottomConstraint =[_messageInputContainerView.bottomAnchor constraintEqualToAnchor:_inputTextView.bottomAnchorconstant:_bottomAreaInset];_inputBottomConstraint.active = YES;self.sendBottomConstraint =[_messageInputContainerView.bottomAnchor constraintEqualToAnchor:_sendButton.bottomAnchorconstant:_bottomAreaInset + 6];_sendBottomConstraint.active = YES;[_messageInputContainerView addConstraintsWithFormat:@"V:|[v0(0.5)]" views:@[ topBorderView ]];}- (void)viewWillAppear:(BOOL)animated {[super viewWillAppear:animated];[_inputTextView becomeFirstResponder];}- (void)viewWillDisappear:(BOOL)animated {[_inputTextView endEditing:YES];[super viewWillDisappear:animated];}- (void)enterPressed {NSString *text = _inputTextView.text;if (text.length > 0) {FIRTextMessage *message =[[FIRTextMessage alloc] initWithText:texttimestamp:[NSDate date].timeIntervalSince1970userID:@""isLocalUser:_isLocalUser];[_messages addObject:message];[self.collectionViewinsertItemsAtIndexPaths:@[ [NSIndexPath indexPathForItem:_messages.count - 1inSection:0] ]];_inputTextView.text = nil;[_inputTextView textViewDidChange:_inputTextView];[self clearChips];}[_inputTextView endEditing:YES];}- (IBAction)didTapMore:(UIBarButtonItem *)sender {self.moreAlert.popoverPresentationController.barButtonItem = sender;[self presentViewController:self.moreAlert animated:YES completion:nil];}- (void)clearChips {for (UIView *view in self.smartReplyView.arrangedSubviews) {view.hidden = YES;}}- (void)updateReplies {// SmartReply for users' own messages is a non-use-case.FIRTextMessage *lastMessage = _messages.lastObject;if (lastMessage == nil || lastMessage.isLocalUser == _isLocalUser) {[self clearChips];return;}NSMutableArray<FIRTextMessage *> *chat = _messages;// Revert isLocalUser field in text messages to simulate the remote user for the sample.if (!_isLocalUser) {chat = [[NSMutableArray alloc] initWithCapacity:10];for (int i = (_messages.count <= 10 ? 0 : _messages.count - 10); i < _messages.count; i++) {FIRTextMessage *textMessage = _messages[i];textMessage = [[FIRTextMessage alloc] initWithText:textMessage.texttimestamp:textMessage.timestampuserID:textMessage.userIDisLocalUser:!textMessage.isLocalUser];[chat addObject:textMessage];}}[_smartReplysuggestRepliesForMessages:chatcompletion:^(FIRSmartReplySuggestionResult *_Nullable result,NSError *_Nullable error) {if (error != nil || result == nil || result.suggestions.count == 0) {[self clearChips];return;}for (int i = 0; i < 3; i++) {MDCChipView *chip = self.smartReplyView.arrangedSubviews[i];chip.titleLabel.text = result.suggestions[i].text;[chip sizeToFit];chip.hidden = NO;for (NSLayoutConstraint *constraint in chip.constraints) {if ([constraint.identifier isEqualToString:@"width"]) {constraint.constant = chip.bounds.size.width;break;}}}}];}- (void)handleKeyboardNotification:(NSNotification *)notification {CGRect keyboardSize =((NSValue *)notification.userInfo[UIKeyboardFrameEndUserInfoKey]).CGRectValue;BOOL isKeyboardShowing = notification.name == UIKeyboardWillShowNotification;if (_isKeyboardShown == isKeyboardShowing) {_bottomConstraint.constant = isKeyboardShowing ? -keyboardSize.size.height : 0;if (self.messages.count > 0) {NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.messages.count - 1inSection:0];[self.collectionView scrollToItemAtIndexPath:indexPathatScrollPosition:UICollectionViewScrollPositionTopanimated:YES];}return;}_isKeyboardShown = isKeyboardShowing;_bottomConstraint.constant = isKeyboardShowing ? -keyboardSize.size.height : 0;double inset = isKeyboardShowing ? -_bottomAreaInset : _bottomAreaInset;_heightConstraint.constant += inset;_inputBottomConstraint.constant = isKeyboardShowing ? 0 : _bottomAreaInset;_sendBottomConstraint.constant = isKeyboardShowing ? 6 : (6 + _bottomAreaInset);NSTimeInterval animationDuration =((NSNumber *)notification.userInfo[UIKeyboardAnimationDurationUserInfoKey]).doubleValue;[UIView animateWithDuration:animationDurationdelay:0options:UIViewAnimationOptionCurveEaseOutanimations:^{[self.view layoutIfNeeded];}completion:^(BOOL finished) {if (self.messages.count > 0) {NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.messages.count - 1inSection:0];[self.collectionView scrollToItemAtIndexPath:indexPathatScrollPosition:UICollectionViewScrollPositionTopanimated:YES];}}];}- (void)textViewDidBeginEditing:(UITextView *)textView {[self textViewDidChange:textView];}- (void)collectionView:(UICollectionView *)collectionViewdidSelectItemAtIndexPath:(NSIndexPath *)indexPath {[_inputTextView endEditing:YES];}- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionViewcellForItemAtIndexPath:(NSIndexPath *)indexPath {MDCSelfSizingStereoCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell"forIndexPath:indexPath];FIRTextMessage *item = _messages[indexPath.item];cell.leadingImageView.image = [UIImage imageNamed:@"ic_account_circle_36pt"];cell.leadingImageView.tintColor = item.isLocalUser ? UIColor.blueColor : UIColor.redColor;cell.titleLabel.text = item.text;cell.detailLabel.text = [[NSDate dateWithTimeIntervalSince1970:item.timestamp] timeAgo];return cell;}- (void)replySelected:(MDCChipView *)reply {[_inputTextView insertText:reply.titleLabel.text];}- (IBAction)switchUser:(id)sender {self.isLocalUser = !_isLocalUser;UIColor *color = _isLocalUser ? UIColor.blueColor : UIColor.redColor;_sendButton.tintColor = color;self.navigationController.navigationBar.barTintColor = color;[self updateReplies];}- (void)generateChatHistoryBasic {NSDate *date = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitDayvalue:-1toDate:[NSDate date]options:0];NSTimeInterval dateAfter = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitMinutevalue:10toDate:dateoptions:0].timeIntervalSince1970;_messages =@[[[FIRTextMessage alloc] initWithText:@"Hello"timestamp:date.timeIntervalSince1970userID:@""isLocalUser:YES],[[FIRTextMessage alloc] initWithText:@"Hey" timestamp:dateAfter userID:@"" isLocalUser:NO]].mutableCopy;[self updateReplies];[self.collectionView reloadData];}- (void)generateChatHistoryWithSensitiveContent {NSDate *date = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitDayvalue:-1toDate:[NSDate date]options:0];NSTimeInterval dateAfter = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitMinutevalue:10toDate:dateoptions:0].timeIntervalSince1970;NSTimeInterval dateAfterAfter = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitMinutevalue:20toDate:dateoptions:0].timeIntervalSince1970;_messages =@[[[FIRTextMessage alloc] initWithText:@"Hi"timestamp:date.timeIntervalSince1970userID:@""isLocalUser:NO],[[FIRTextMessage alloc] initWithText:@"How are you?"timestamp:dateAfteruserID:@""isLocalUser:YES],[[FIRTextMessage alloc] initWithText:@"My cat died"timestamp:dateAfterAfteruserID:@""isLocalUser:NO]].mutableCopy;[self updateReplies];[self.collectionView reloadData];}- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {return 1;}- (void)textViewDidEndEditing:(UITextView *)textView {_sendButton.enabled = NO;_heightConstraint.constant = 88 + _bottomAreaInset;}- (void)textViewDidChange:(UITextView *)textView {_sendButton.enabled = textView.text.length != 0;CGSize size = CGSizeMake(self.view.frame.size.width - 60, INFINITY);CGSize estimatedSize = [textView sizeThatFits:size];_heightConstraint.constant =estimatedSize.height + 54 + (self.isKeyboardShown ? 0 : _bottomAreaInset);}- (NSInteger)collectionView:(UICollectionView *)collectionViewnumberOfItemsInSection:(NSInteger)section {return _messages.count;}@endNS_ASSUME_NONNULL_END
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。