element-ios/Riot/Modules/Room/Views/InputToolbar/RoomInputToolbarView.m

442 lines
15 KiB
Mathematica
Raw Normal View History

2015-08-18 08:04:30 +00:00
/*
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
2015-08-18 08:04:30 +00:00
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 "RoomInputToolbarView.h"
#import "ThemeService.h"
#import "Riot-Swift.h"
#import "GBDeviceInfo_iOS.h"
#import "UINavigationController+Riot.h"
#import "WidgetManager.h"
#import "IntegrationManagerViewController.h"
2021-04-08 10:11:36 +00:00
const double kContextBarHeight = 24;
const NSTimeInterval kSendModeAnimationDuration = .15;
const NSTimeInterval kActionMenuAttachButtonAnimationDuration = .4;
const CGFloat kActionMenuAttachButtonSpringVelocity = 7;
const CGFloat kActionMenuAttachButtonSpringDamping = .45;
const NSTimeInterval kActionMenuContentAlphaAnimationDuration = .2;
const NSTimeInterval kActionMenuComposerHeightAnimationDuration = .3;
@interface RoomInputToolbarView()
2015-08-18 08:04:30 +00:00
{
// The intermediate action sheet
UIAlertController *actionSheet;
2015-08-18 08:04:30 +00:00
}
@property (nonatomic, weak) IBOutlet UIView *voiceMessageToolbarContainerView;
@property (nonatomic, strong) VoiceMessageToolbarView *voiceMessageToolbarView;
2015-08-18 08:04:30 +00:00
@end
@implementation RoomInputToolbarView
@dynamic delegate;
2015-08-18 08:04:30 +00:00
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass([RoomInputToolbarView class])
bundle:[NSBundle bundleForClass:[RoomInputToolbarView class]]];
}
+ (instancetype)roomInputToolbarView
{
if ([[self class] nib])
{
return [[[self class] nib] instantiateWithOwner:nil options:nil].firstObject;
}
else
{
return [[self alloc] init];
}
}
- (void)awakeFromNib
{
[super awakeFromNib];
_sendMode = RoomInputToolbarViewSendModeSend;
self.inputContextViewHeightConstraint.constant = 0;
[self.rightInputToolbarButton setTitle:nil forState:UIControlStateNormal];
[self.rightInputToolbarButton setTitle:nil forState:UIControlStateHighlighted];
self.isEncryptionEnabled = _isEncryptionEnabled;
self.voiceMessageToolbarView = [VoiceMessageToolbarView instanceFromNib];
self.voiceMessageToolbarView.frame = self.voiceMessageToolbarContainerView.bounds;
self.voiceMessageToolbarView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.voiceMessageToolbarContainerView addSubview:self.voiceMessageToolbarView];
[self _updateUIWithTextMessage:nil animated:NO];
}
#pragma mark - Override MXKView
-(void)customizeViewRendering
{
[super customizeViewRendering];
// Remove default toolbar background color
self.backgroundColor = [UIColor clearColor];
// Custom the growingTextView display
growingTextView.layer.cornerRadius = 0;
growingTextView.layer.borderWidth = 0;
growingTextView.backgroundColor = [UIColor clearColor];
growingTextView.font = [UIFont systemFontOfSize:15];
2019-01-11 10:45:27 +00:00
growingTextView.textColor = ThemeService.shared.theme.textPrimaryColor;
growingTextView.tintColor = ThemeService.shared.theme.tintColor;
growingTextView.placeholderColor = ThemeService.shared.theme.textTertiaryColor;
growingTextView.internalTextView.showsVerticalScrollIndicator = NO;
2019-01-11 10:45:27 +00:00
growingTextView.internalTextView.keyboardAppearance = ThemeService.shared.theme.keyboardAppearance;
if (growingTextView.isFirstResponder)
{
[growingTextView resignFirstResponder];
[growingTextView becomeFirstResponder];
}
self.attachMediaButton.accessibilityLabel = NSLocalizedStringFromTable(@"room_accessibility_upload", @"Vector", nil);
UIImage *image = [UIImage imageNamed:@"input_text_background"];
image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(9, 15, 10, 16)];
self.inputTextBackgroundView.image = image;
self.inputTextBackgroundView.tintColor = ThemeService.shared.theme.roomInputTextBorder;
if ([ThemeService.shared.themeId isEqualToString:@"light"])
{
[self.attachMediaButton setImage:[UIImage imageNamed:@"upload_icon"] forState:UIControlStateNormal];
}
else if ([ThemeService.shared.themeId isEqualToString:@"dark"] || [ThemeService.shared.themeId isEqualToString:@"black"])
{
[self.attachMediaButton setImage:[UIImage imageNamed:@"upload_icon_dark"] forState:UIControlStateNormal];
}
else if (@available(iOS 12.0, *) && ThemeService.shared.theme.userInterfaceStyle == UIUserInterfaceStyleDark) {
[self.attachMediaButton setImage:[UIImage imageNamed:@"upload_icon_dark"] forState:UIControlStateNormal];
}
self.inputContextImageView.tintColor = ThemeService.shared.theme.textSecondaryColor;
self.inputContextLabel.textColor = ThemeService.shared.theme.textSecondaryColor;
self.inputContextButton.tintColor = ThemeService.shared.theme.textSecondaryColor;
2021-04-08 10:11:36 +00:00
[self.actionsBar updateWithTheme:ThemeService.shared.theme];
[self.voiceMessageToolbarView updateWithTheme:ThemeService.shared.theme];
2015-08-18 08:04:30 +00:00
}
#pragma mark -
- (void)setTextMessage:(NSString *)textMessage
{
[self _updateUIWithTextMessage:textMessage animated:YES];
[super setTextMessage:textMessage];
}
- (void)setIsEncryptionEnabled:(BOOL)isEncryptionEnabled
{
_isEncryptionEnabled = isEncryptionEnabled;
[self updatePlaceholder];
}
- (void)setSendMode:(RoomInputToolbarViewSendMode)sendMode
{
RoomInputToolbarViewSendMode previousMode = _sendMode;
_sendMode = sendMode;
self.actionMenuOpened = NO;
[self updatePlaceholder];
[self updateToolbarButtonLabelWithPreviousMode: previousMode];
}
- (void)updateToolbarButtonLabelWithPreviousMode:(RoomInputToolbarViewSendMode)previousMode
{
UIImage *buttonImage;
double updatedHeight = self.mainToolbarHeightConstraint.constant;
switch (_sendMode)
{
case RoomInputToolbarViewSendModeReply:
buttonImage = [UIImage imageNamed:@"send_icon"];
self.inputContextImageView.image = [UIImage imageNamed:@"input_reply_icon"];
self.inputContextLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_message_replying_to", @"Vector", nil), self.eventSenderDisplayName];
2021-04-08 10:11:36 +00:00
self.inputContextViewHeightConstraint.constant = kContextBarHeight;
updatedHeight += kContextBarHeight;
self->growingTextView.maxHeight -= kContextBarHeight;
break;
case RoomInputToolbarViewSendModeEdit:
buttonImage = [UIImage imageNamed:@"save_icon"];
self.inputContextImageView.image = [UIImage imageNamed:@"input_edit_icon"];
self.inputContextLabel.text = NSLocalizedStringFromTable(@"room_message_editing", @"Vector", nil);
2021-04-08 10:11:36 +00:00
self.inputContextViewHeightConstraint.constant = kContextBarHeight;
updatedHeight += kContextBarHeight;
self->growingTextView.maxHeight -= kContextBarHeight;
break;
default:
buttonImage = [UIImage imageNamed:@"send_icon"];
if (previousMode != _sendMode)
{
2021-04-08 10:11:36 +00:00
updatedHeight -= kContextBarHeight;
self->growingTextView.maxHeight += kContextBarHeight;
}
self.inputContextViewHeightConstraint.constant = 0;
break;
}
[self.rightInputToolbarButton setImage:buttonImage forState:UIControlStateNormal];
if (self.maxHeight && updatedHeight > self.maxHeight)
{
growingTextView.maxHeight -= updatedHeight - self.maxHeight;
updatedHeight = self.maxHeight;
}
if (updatedHeight < self.mainToolbarMinHeightConstraint.constant)
{
updatedHeight = self.mainToolbarMinHeightConstraint.constant;
}
if (self.mainToolbarHeightConstraint.constant != updatedHeight)
{
2021-04-08 10:11:36 +00:00
[UIView animateWithDuration:kSendModeAnimationDuration animations:^{
self.mainToolbarHeightConstraint.constant = updatedHeight;
[self layoutIfNeeded];
// Update toolbar superview
if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:heightDidChanged:completion:)])
{
[self.delegate roomInputToolbarView:self heightDidChanged:updatedHeight completion:nil];
}
}];
}
}
- (void)updatePlaceholder
{
// Consider the default placeholder
NSString *placeholder;
// Check the device screen size before using large placeholder
BOOL shouldDisplayLargePlaceholder = [GBDeviceInfo deviceInfo].family == GBDeviceFamilyiPad || [GBDeviceInfo deviceInfo].displayInfo.display >= GBDeviceDisplay5p8Inch;
if (!shouldDisplayLargePlaceholder)
{
switch (_sendMode)
{
case RoomInputToolbarViewSendModeReply:
placeholder = NSLocalizedStringFromTable(@"room_message_reply_to_short_placeholder", @"Vector", nil);
break;
default:
placeholder = NSLocalizedStringFromTable(@"room_message_short_placeholder", @"Vector", nil);
break;
}
}
else
{
if (_isEncryptionEnabled)
{
switch (_sendMode)
{
case RoomInputToolbarViewSendModeReply:
placeholder = NSLocalizedStringFromTable(@"encrypted_room_message_reply_to_placeholder", @"Vector", nil);
break;
default:
placeholder = NSLocalizedStringFromTable(@"encrypted_room_message_placeholder", @"Vector", nil);
break;
}
}
else
{
switch (_sendMode)
{
case RoomInputToolbarViewSendModeReply:
placeholder = NSLocalizedStringFromTable(@"room_message_reply_to_placeholder", @"Vector", nil);
break;
default:
placeholder = NSLocalizedStringFromTable(@"room_message_placeholder", @"Vector", nil);
break;
}
}
}
self.placeholder = placeholder;
}
#pragma mark - Actions
- (IBAction)cancelAction:(id)sender
{
if ([self.delegate respondsToSelector:@selector(roomInputToolbarViewDidTapCancel:)])
{
[self.delegate roomInputToolbarViewDidTapCancel:self];
}
}
2015-08-18 08:04:30 +00:00
#pragma mark - HPGrowingTextView delegate
- (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSString *newText = [growingTextView.text stringByReplacingCharactersInRange:range withString:text];
[self _updateUIWithTextMessage:newText animated:YES];
return YES;
}
- (void)growingTextViewDidChange:(HPGrowingTextView *)hpGrowingTextView
2015-08-18 08:04:30 +00:00
{
2015-08-18 08:51:28 +00:00
// Clean the carriage return added on return press
if ([self.textMessage isEqualToString:@"\n"])
2015-08-18 08:04:30 +00:00
{
2015-08-18 08:51:28 +00:00
self.textMessage = nil;
2015-08-18 08:04:30 +00:00
}
[super growingTextViewDidChange:hpGrowingTextView];
2015-08-18 08:04:30 +00:00
}
- (void)growingTextView:(HPGrowingTextView *)hpGrowingTextView willChangeHeight:(float)height
2015-08-18 14:24:48 +00:00
{
// Update height of the main toolbar (message composer)
CGFloat updatedHeight = height + (self.messageComposerContainerTopConstraint.constant + self.messageComposerContainerBottomConstraint.constant) + self.inputContextViewHeightConstraint.constant;
if (self.maxHeight && updatedHeight > self.maxHeight)
{
hpGrowingTextView.maxHeight -= updatedHeight - self.maxHeight;
updatedHeight = self.maxHeight;
}
if (updatedHeight < self.mainToolbarMinHeightConstraint.constant)
{
updatedHeight = self.mainToolbarMinHeightConstraint.constant;
}
self.mainToolbarHeightConstraint.constant = updatedHeight;
// Update toolbar superview
if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:heightDidChanged:completion:)])
{
[self.delegate roomInputToolbarView:self heightDidChanged:updatedHeight completion:nil];
}
2015-08-18 14:24:48 +00:00
}
2015-08-18 08:04:30 +00:00
#pragma mark - Override MXKRoomInputToolbarView
- (IBAction)onTouchUpInside:(UIButton*)button
{
2015-08-18 08:51:28 +00:00
if (button == self.attachMediaButton)
2015-08-18 08:04:30 +00:00
{
self.actionMenuOpened = !self.isActionMenuOpened;
2015-08-18 08:04:30 +00:00
}
2015-08-18 08:51:28 +00:00
[super onTouchUpInside:button];
2015-08-18 08:04:30 +00:00
}
- (void)destroy
{
if (actionSheet)
{
[actionSheet dismissViewControllerAnimated:NO completion:nil];
actionSheet = nil;
}
2015-08-18 08:04:30 +00:00
[super destroy];
}
#pragma mark - properties
- (void)setActionMenuOpened:(BOOL)actionMenuOpened
{
if (_actionMenuOpened != actionMenuOpened)
{
_actionMenuOpened = actionMenuOpened;
if (self->growingTextView.internalTextView.selectedRange.length > 0)
{
NSRange range = self->growingTextView.internalTextView.selectedRange;
range.location = range.location + range.length;
range.length = 0;
self->growingTextView.internalTextView.selectedRange = range;
}
if (_actionMenuOpened) {
self.actionsBar.hidden = NO;
[self.actionsBar animateWithShowIn:_actionMenuOpened completion:nil];
}
else
{
[self.actionsBar animateWithShowIn:_actionMenuOpened completion:^(BOOL finished) {
self.actionsBar.hidden = YES;
}];
}
2021-04-08 10:11:36 +00:00
[UIView animateWithDuration:kActionMenuAttachButtonAnimationDuration delay:0 usingSpringWithDamping:kActionMenuAttachButtonSpringDamping initialSpringVelocity:kActionMenuAttachButtonSpringVelocity options:UIViewAnimationOptionCurveEaseIn animations:^{
self.attachMediaButton.transform = actionMenuOpened ? CGAffineTransformMakeRotation(M_PI * 3 / 4) : CGAffineTransformIdentity;
2021-04-08 10:11:36 +00:00
} completion:nil];
2021-04-08 10:11:36 +00:00
[UIView animateWithDuration:kActionMenuContentAlphaAnimationDuration delay:_actionMenuOpened ? 0 : .1 options:UIViewAnimationOptionCurveEaseIn animations:^{
self->messageComposerContainer.alpha = actionMenuOpened ? 0 : 1;
self.rightInputToolbarButton.alpha = self->growingTextView.text.length == 0 || actionMenuOpened ? 0 : 1;
2021-04-08 10:11:36 +00:00
} completion:nil];
2021-04-08 10:11:36 +00:00
[UIView animateWithDuration:kActionMenuComposerHeightAnimationDuration animations:^{
if (actionMenuOpened)
{
self.mainToolbarHeightConstraint.constant = self.mainToolbarMinHeightConstraint.constant;
}
else
{
[self->growingTextView refreshHeight];
}
[self layoutIfNeeded];
[self.delegate roomInputToolbarView:self heightDidChanged:self.mainToolbarHeightConstraint.constant completion:nil];
}];
}
}
#pragma mark - Clipboard - Handle image/data paste from general pasteboard
- (void)paste:(id)sender
{
// TODO Custom here the validation screen for each available item
[super paste:sender];
}
#pragma mark - Private
- (void)_updateUIWithTextMessage:(NSString *)textMessage animated:(BOOL)animated
{
self.actionMenuOpened = NO;
[UIView animateWithDuration:(animated ? 0.15f : 0.0f) animations:^{
self.rightInputToolbarButton.alpha = textMessage.length ? 1.0f : 0.0f;
self.voiceMessageToolbarContainerView.alpha = textMessage.length ? 0.0f : 1.0;
}];
}
2015-08-18 08:04:30 +00:00
@end