mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-20 16:42:44 +02:00
Merge branch 'develop' into voip_design_updates
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// 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 UIKit
|
||||
|
||||
@objcMembers
|
||||
class RoomTypingBubbleCell: MXKTableViewCell, Themable {
|
||||
// MARK: - Constants
|
||||
|
||||
private enum Constants {
|
||||
static let maxPictureCount = 4
|
||||
static let pictureSize: CGFloat = 24
|
||||
static let pictureMaxMargin: CGFloat = 16
|
||||
static let pictureMinMargin: CGFloat = 8
|
||||
}
|
||||
|
||||
// MARK: - Outlets
|
||||
|
||||
@IBOutlet private weak var additionalUsersLabel: UILabel!
|
||||
@IBOutlet private weak var additionalUsersLabelLeadingConstraint: NSLayoutConstraint!
|
||||
@IBOutlet private weak var dotsView: DotsView!
|
||||
@IBOutlet private weak var dotsViewLeadingConstraint: NSLayoutConstraint!
|
||||
|
||||
// MARK: - members
|
||||
|
||||
private var userPictureViews: [MXKImageView] = []
|
||||
|
||||
// MARK: - Lifecycle
|
||||
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
update(theme: ThemeService.shared().theme)
|
||||
}
|
||||
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
|
||||
for pictureView in userPictureViews {
|
||||
pictureView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
dotsView.isHidden = userPictureViews.count == 0
|
||||
|
||||
guard userPictureViews.count > 0 else {
|
||||
return
|
||||
}
|
||||
|
||||
additionalUsersLabel?.sizeToFit()
|
||||
|
||||
var pictureViewsMaxX: CGFloat = 0
|
||||
var xOffset: CGFloat = 0
|
||||
for pictureView in userPictureViews {
|
||||
pictureView.center = CGPoint(x: Constants.pictureMaxMargin + xOffset + pictureView.bounds.midX, y: self.bounds.midY)
|
||||
xOffset += round(pictureView.bounds.maxX * 2 / 3)
|
||||
pictureViewsMaxX = pictureView.frame.maxX
|
||||
}
|
||||
|
||||
let leftMagin: CGFloat = pictureViewsMaxX + (userPictureViews.count == 1 ? Constants.pictureMaxMargin : Constants.pictureMinMargin)
|
||||
additionalUsersLabelLeadingConstraint.constant = leftMagin
|
||||
|
||||
dotsViewLeadingConstraint?.constant = additionalUsersLabel.text.isEmptyOrNil == true ? leftMagin : leftMagin + 8 + additionalUsersLabel.frame.width
|
||||
}
|
||||
|
||||
// MARK: - Overrides
|
||||
|
||||
override class func defaultReuseIdentifier() -> String {
|
||||
return String(describing: self)
|
||||
}
|
||||
|
||||
override class func nib() -> UINib {
|
||||
return UINib(nibName: String(describing: self), bundle: nil)
|
||||
}
|
||||
|
||||
// MARK: - Themable
|
||||
|
||||
func update(theme: Theme) {
|
||||
additionalUsersLabel.textColor = theme.textSecondaryColor
|
||||
dotsView.highlightedDotColor = theme.textTertiaryColor
|
||||
dotsView.dotColor = theme.textSecondaryColor
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Business methods
|
||||
|
||||
func updateTypingUsers(_ typingUsers: [TypingUserInfo], mediaManager: MXMediaManager) {
|
||||
for pictureView in userPictureViews {
|
||||
pictureView.removeFromSuperview()
|
||||
}
|
||||
userPictureViews = []
|
||||
|
||||
for user in typingUsers {
|
||||
if userPictureViews.count >= Constants.maxPictureCount {
|
||||
break
|
||||
}
|
||||
|
||||
let pictureView = MXKImageView(frame: CGRect(x: 0, y: 0, width: Constants.pictureSize, height: Constants.pictureSize))
|
||||
pictureView.layer.masksToBounds = true
|
||||
pictureView.layer.cornerRadius = pictureView.bounds.midX
|
||||
|
||||
let defaultavatarImage = AvatarGenerator.generateAvatar(forMatrixItem: user.userId, withDisplayName: user.displayName)
|
||||
pictureView.setImageURI(user.avatarUrl, withType: nil, andImageOrientation: .up, toFitViewSize: pictureView.bounds.size, with: MXThumbnailingMethodCrop, previewImage: defaultavatarImage, mediaManager: mediaManager)
|
||||
|
||||
userPictureViews.append(pictureView)
|
||||
self.contentView.addSubview(pictureView)
|
||||
}
|
||||
|
||||
switch typingUsers.count {
|
||||
case 0:
|
||||
additionalUsersLabel.text = nil
|
||||
case 1:
|
||||
additionalUsersLabel.text = firstUserNameFor(typingUsers)
|
||||
default:
|
||||
additionalUsersLabel.text = VectorL10n.roomMultipleTypingNotification(firstUserNameFor(typingUsers) ?? "")
|
||||
}
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
|
||||
private func firstUserNameFor(_ typingUsers: Array<TypingUserInfo>) -> String? {
|
||||
guard let firstUser = typingUsers.first else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return firstUser.displayName.isEmptyOrNil ? firstUser.userId : firstUser.displayName
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="none" indentationWidth="10" id="nQB-23-kip" customClass="RoomTypingBubbleCell" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" preservesSuperviewLayoutMargins="YES" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="nQB-23-kip" id="vRo-3W-dC9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="+3" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="4KE-u0-T4p">
|
||||
<rect key="frame" x="20" y="13" width="18.5" height="18"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Bn5-WN-DQs" customClass="DotsView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="38" y="13" width="91" height="18"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="4KE-u0-T4p" firstAttribute="leading" secondItem="vRo-3W-dC9" secondAttribute="leading" constant="20" symbolic="YES" id="PFN-Ig-2NK"/>
|
||||
<constraint firstItem="Bn5-WN-DQs" firstAttribute="leading" secondItem="vRo-3W-dC9" secondAttribute="leading" constant="38" id="hmq-dH-neQ"/>
|
||||
<constraint firstItem="Bn5-WN-DQs" firstAttribute="centerY" secondItem="vRo-3W-dC9" secondAttribute="centerY" id="jup-hc-eNQ"/>
|
||||
</constraints>
|
||||
</tableViewCellContentView>
|
||||
<constraints>
|
||||
<constraint firstItem="4KE-u0-T4p" firstAttribute="centerY" secondItem="nQB-23-kip" secondAttribute="centerY" id="hBP-OB-KGd"/>
|
||||
</constraints>
|
||||
<connections>
|
||||
<outlet property="additionalUsersLabel" destination="4KE-u0-T4p" id="SVG-Oa-aHI"/>
|
||||
<outlet property="additionalUsersLabelLeadingConstraint" destination="PFN-Ig-2NK" id="4Wr-XS-XXp"/>
|
||||
<outlet property="dotsView" destination="Bn5-WN-DQs" id="QqF-bu-Pbm"/>
|
||||
<outlet property="dotsViewLeadingConstraint" destination="hmq-dH-neQ" id="6hM-Sc-pCc"/>
|
||||
</connections>
|
||||
<point key="canvasLocation" x="166.66666666666669" y="20.758928571428569"/>
|
||||
</tableViewCell>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// 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 UIKit
|
||||
|
||||
@objcMembers
|
||||
class RoomActionItem: NSObject {
|
||||
let image: UIImage
|
||||
let action: (() -> Void)
|
||||
|
||||
init(image: UIImage, andAction action: @escaping () -> Void) {
|
||||
self.image = image
|
||||
self.action = action
|
||||
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// 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 UIKit
|
||||
|
||||
@objcMembers
|
||||
class RoomActionsBar: UIScrollView, Themable {
|
||||
// MARK: - Properties
|
||||
|
||||
var itemSpacing: CGFloat = 20 {
|
||||
didSet {
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
var actionItems: [RoomActionItem] = [] {
|
||||
didSet {
|
||||
var actionButtons: [UIButton] = []
|
||||
for (index, item) in actionItems.enumerated() {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(item.image, for: .normal)
|
||||
button.addTarget(self, action: #selector(buttonAction(_:)), for: .touchUpInside)
|
||||
button.tintColor = ThemeService.shared().theme.tintColor
|
||||
button.tag = index
|
||||
actionButtons.append(button)
|
||||
addSubview(button)
|
||||
}
|
||||
self.actionButtons = actionButtons
|
||||
self.lastBounds = .zero
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private var actionButtons: [UIButton] = [] {
|
||||
willSet {
|
||||
for button in actionButtons {
|
||||
button.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var lastBounds = CGRect.zero
|
||||
|
||||
// MARK: - Lifecycle
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setupView()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
setupView()
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
guard lastBounds != self.bounds else {
|
||||
return
|
||||
}
|
||||
|
||||
lastBounds = self.bounds
|
||||
|
||||
var currentX: CGFloat = 0
|
||||
for button in actionButtons {
|
||||
button.transform = CGAffineTransform.identity
|
||||
button.frame = CGRect(x: currentX, y: 0, width: self.bounds.height, height: self.bounds.height)
|
||||
currentX = button.frame.maxX + itemSpacing
|
||||
}
|
||||
|
||||
self.contentSize = CGSize(width: currentX - itemSpacing, height: self.bounds.height)
|
||||
}
|
||||
|
||||
// MARK: - Themable
|
||||
|
||||
func update(theme: Theme) {
|
||||
for button in actionButtons {
|
||||
button.tintColor = theme.tintColor
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Business methods
|
||||
|
||||
func animate(showIn: Bool, completion: ((Bool) -> Void)? = nil) {
|
||||
if showIn {
|
||||
for button in actionButtons {
|
||||
button.transform = CGAffineTransform(translationX: 0, y: self.bounds.height)
|
||||
}
|
||||
for (index, button) in actionButtons.enumerated() {
|
||||
UIView.animate(withDuration: 0.3, delay: 0.05 * Double(index), usingSpringWithDamping: 0.45, initialSpringVelocity: 11, options: .curveEaseInOut) {
|
||||
button.transform = CGAffineTransform.identity
|
||||
} completion: { (finished) in
|
||||
completion?(finished)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (index, button) in actionButtons.enumerated() {
|
||||
UIView.animate(withDuration: 0.25, delay: 0.05 * Double(index), options: .curveEaseInOut) {
|
||||
button.transform = CGAffineTransform(translationX: 0, y: self.bounds.height)
|
||||
} completion: { (finished) in
|
||||
if index == self.actionButtons.count - 1 {
|
||||
completion?(finished)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
@objc private func buttonAction(_ sender: UIButton) {
|
||||
actionItems[sender.tag].action()
|
||||
}
|
||||
|
||||
private func setupView() {
|
||||
self.showsHorizontalScrollIndicator = false
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
#import "MediaPickerViewController.h"
|
||||
|
||||
@class RoomActionsBar;
|
||||
|
||||
/**
|
||||
Destination of the message in the composer
|
||||
*/
|
||||
@@ -31,34 +33,6 @@ typedef enum : NSUInteger
|
||||
|
||||
@protocol RoomInputToolbarViewDelegate <MXKRoomInputToolbarViewDelegate>
|
||||
|
||||
/**
|
||||
Tells the delegate that the user wants to display the sticker picker.
|
||||
|
||||
@param toolbarView the room input toolbar view.
|
||||
*/
|
||||
- (void)roomInputToolbarViewPresentStickerPicker:(MXKRoomInputToolbarView*)toolbarView;
|
||||
|
||||
/**
|
||||
Tells the delegate that the user wants to send external files.
|
||||
|
||||
@param toolbarView the room input toolbar view
|
||||
*/
|
||||
- (void)roomInputToolbarViewDidTapFileUpload:(MXKRoomInputToolbarView*)toolbarView;
|
||||
|
||||
/**
|
||||
Tells the delegate that the user wants to take photo or video with camera.
|
||||
|
||||
@param toolbarView the room input toolbar view
|
||||
*/
|
||||
- (void)roomInputToolbarViewDidTapCamera:(MXKRoomInputToolbarView*)toolbarView;
|
||||
|
||||
/**
|
||||
Tells the delegate that the user wants to show media library.
|
||||
|
||||
@param toolbarView the room input toolbar view
|
||||
*/
|
||||
- (void)roomInputToolbarViewDidTapMediaLibrary:(MXKRoomInputToolbarView*)toolbarView;
|
||||
|
||||
/**
|
||||
Tells the delegate that the user wants to cancel the current edition / reply.
|
||||
|
||||
@@ -95,6 +69,7 @@ typedef enum : NSUInteger
|
||||
@property (weak, nonatomic) IBOutlet UIImageView *inputContextImageView;
|
||||
@property (weak, nonatomic) IBOutlet UILabel *inputContextLabel;
|
||||
@property (weak, nonatomic) IBOutlet UIButton *inputContextButton;
|
||||
@property (weak, nonatomic) IBOutlet RoomActionsBar *actionsBar;
|
||||
|
||||
/**
|
||||
Tell whether the filled data will be sent encrypted. NO by default.
|
||||
@@ -111,4 +86,9 @@ typedef enum : NSUInteger
|
||||
*/
|
||||
@property (nonatomic) RoomInputToolbarViewSendMode sendMode;
|
||||
|
||||
/**
|
||||
YES if action menu is opened. NO otherwise
|
||||
*/
|
||||
@property (nonatomic, getter=isActionMenuOpened) BOOL actionMenuOpened;
|
||||
|
||||
@end
|
||||
|
||||
@@ -27,7 +27,13 @@
|
||||
#import "WidgetManager.h"
|
||||
#import "IntegrationManagerViewController.h"
|
||||
|
||||
const double RoomInputToolbarViewContextBarHeight = 30;
|
||||
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()
|
||||
{
|
||||
@@ -120,6 +126,7 @@ const double RoomInputToolbarViewContextBarHeight = 30;
|
||||
self.inputContextImageView.tintColor = ThemeService.shared.theme.textSecondaryColor;
|
||||
self.inputContextLabel.textColor = ThemeService.shared.theme.textSecondaryColor;
|
||||
self.inputContextButton.tintColor = ThemeService.shared.theme.textSecondaryColor;
|
||||
[self.actionsBar updateWithTheme:ThemeService.shared.theme];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
@@ -142,6 +149,7 @@ const double RoomInputToolbarViewContextBarHeight = 30;
|
||||
RoomInputToolbarViewSendMode previousMode = _sendMode;
|
||||
_sendMode = sendMode;
|
||||
|
||||
self.actionMenuOpened = NO;
|
||||
[self updatePlaceholder];
|
||||
[self updateToolbarButtonLabelWithPreviousMode: previousMode];
|
||||
}
|
||||
@@ -159,26 +167,26 @@ const double RoomInputToolbarViewContextBarHeight = 30;
|
||||
self.inputContextImageView.image = [UIImage imageNamed:@"input_reply_icon"];
|
||||
self.inputContextLabel.text = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_message_replying_to", @"Vector", nil), self.eventSenderDisplayName];
|
||||
|
||||
self.inputContextViewHeightConstraint.constant = RoomInputToolbarViewContextBarHeight;
|
||||
updatedHeight += RoomInputToolbarViewContextBarHeight;
|
||||
self->growingTextView.maxHeight -= RoomInputToolbarViewContextBarHeight;
|
||||
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);
|
||||
|
||||
self.inputContextViewHeightConstraint.constant = RoomInputToolbarViewContextBarHeight;
|
||||
updatedHeight += RoomInputToolbarViewContextBarHeight;
|
||||
self->growingTextView.maxHeight -= RoomInputToolbarViewContextBarHeight;
|
||||
self.inputContextViewHeightConstraint.constant = kContextBarHeight;
|
||||
updatedHeight += kContextBarHeight;
|
||||
self->growingTextView.maxHeight -= kContextBarHeight;
|
||||
break;
|
||||
default:
|
||||
buttonImage = [UIImage imageNamed:@"send_icon"];
|
||||
|
||||
if (previousMode != _sendMode)
|
||||
{
|
||||
updatedHeight -= RoomInputToolbarViewContextBarHeight;
|
||||
self->growingTextView.maxHeight += RoomInputToolbarViewContextBarHeight;
|
||||
updatedHeight -= kContextBarHeight;
|
||||
self->growingTextView.maxHeight += kContextBarHeight;
|
||||
}
|
||||
self.inputContextViewHeightConstraint.constant = 0;
|
||||
break;
|
||||
@@ -199,7 +207,7 @@ const double RoomInputToolbarViewContextBarHeight = 30;
|
||||
|
||||
if (self.mainToolbarHeightConstraint.constant != updatedHeight)
|
||||
{
|
||||
[UIView animateWithDuration:.3 animations:^{
|
||||
[UIView animateWithDuration:kSendModeAnimationDuration animations:^{
|
||||
self.mainToolbarHeightConstraint.constant = updatedHeight;
|
||||
[self layoutIfNeeded];
|
||||
|
||||
@@ -329,92 +337,7 @@ const double RoomInputToolbarViewContextBarHeight = 30;
|
||||
{
|
||||
if (button == self.attachMediaButton)
|
||||
{
|
||||
// Check whether media attachment is supported
|
||||
if ([self.delegate respondsToSelector:@selector(roomInputToolbarView:presentViewController:)])
|
||||
{
|
||||
// Ask the user the kind of the call: voice or video?
|
||||
actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
|
||||
[actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_action_camera", @"Vector", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->actionSheet = nil;
|
||||
|
||||
[self.delegate roomInputToolbarViewDidTapCamera:self];
|
||||
}
|
||||
}]];
|
||||
|
||||
|
||||
[actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_action_send_photo_or_video", @"Vector", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->actionSheet = nil;
|
||||
|
||||
[self.delegate roomInputToolbarViewDidTapMediaLibrary:self];
|
||||
}
|
||||
|
||||
}]];
|
||||
|
||||
if (BuildSettings.allowSendingStickers)
|
||||
{
|
||||
[actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_action_send_sticker", @"Vector", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->actionSheet = nil;
|
||||
|
||||
[self.delegate roomInputToolbarViewPresentStickerPicker:self];
|
||||
}
|
||||
|
||||
}]];
|
||||
}
|
||||
|
||||
[actionSheet addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"room_action_send_file", @"Vector", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->actionSheet = nil;
|
||||
|
||||
[self.delegate roomInputToolbarViewDidTapFileUpload:self];
|
||||
}
|
||||
}]];
|
||||
|
||||
[actionSheet addAction:[UIAlertAction actionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction * action) {
|
||||
|
||||
if (weakSelf)
|
||||
{
|
||||
typeof(self) self = weakSelf;
|
||||
self->actionSheet = nil;
|
||||
}
|
||||
|
||||
}]];
|
||||
|
||||
[actionSheet popoverPresentationController].sourceView = self.attachMediaButton;
|
||||
[actionSheet popoverPresentationController].sourceRect = self.attachMediaButton.bounds;
|
||||
[self.window.rootViewController presentViewController:actionSheet animated:YES completion:nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[RoomInputToolbarView] Attach media is not supported");
|
||||
}
|
||||
self.actionMenuOpened = !self.isActionMenuOpened;
|
||||
}
|
||||
|
||||
[super onTouchUpInside:button];
|
||||
@@ -433,6 +356,8 @@ const double RoomInputToolbarViewContextBarHeight = 30;
|
||||
|
||||
- (void)updateSendButtonWithMessage:(NSString *)textMessage
|
||||
{
|
||||
self.actionMenuOpened = NO;
|
||||
|
||||
if (textMessage.length)
|
||||
{
|
||||
self.rightInputToolbarButton.alpha = 1;
|
||||
@@ -443,9 +368,61 @@ const double RoomInputToolbarViewContextBarHeight = 30;
|
||||
self.rightInputToolbarButton.alpha = 0;
|
||||
self.messageComposerContainerTrailingConstraint.constant = 12;
|
||||
}
|
||||
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
#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;
|
||||
}];
|
||||
}
|
||||
|
||||
[UIView animateWithDuration:kActionMenuAttachButtonAnimationDuration delay:0 usingSpringWithDamping:kActionMenuAttachButtonSpringDamping initialSpringVelocity:kActionMenuAttachButtonSpringVelocity options:UIViewAnimationOptionCurveEaseIn animations:^{
|
||||
self.attachMediaButton.transform = actionMenuOpened ? CGAffineTransformMakeRotation(M_PI * 3 / 4) : CGAffineTransformIdentity;
|
||||
} completion:nil];
|
||||
|
||||
[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;
|
||||
} completion:nil];
|
||||
|
||||
[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
|
||||
|
||||
@@ -27,6 +27,14 @@
|
||||
<action selector="onTouchUpInside:" destination="iN0-l3-epB" eventType="touchUpInside" id="WbU-WH-gwL"/>
|
||||
</connections>
|
||||
</button>
|
||||
<scrollView hidden="YES" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ESv-9w-KJF" customClass="RoomActionsBar" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="60" y="8" width="540" height="38"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="38" id="i6C-gL-ADZ"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="contentLayoutGuide" id="F6O-76-cZl"/>
|
||||
<viewLayoutGuide key="frameLayoutGuide" id="rZR-Bv-AqG"/>
|
||||
</scrollView>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QWp-NV-uh5" userLabel="Message Composer Container">
|
||||
<rect key="frame" x="60" y="9" width="528" height="36"/>
|
||||
<subviews>
|
||||
@@ -37,16 +45,16 @@
|
||||
<rect key="frame" x="0.0" y="0.0" width="528" height="32"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="input_edit_icon" translatesAutoresizingMaskIntoConstraints="NO" id="PZ4-0Y-TmL">
|
||||
<rect key="frame" x="12" y="11" width="10.5" height="10"/>
|
||||
<rect key="frame" x="8" y="16" width="10.5" height="10"/>
|
||||
</imageView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dVr-ZM-kkX">
|
||||
<rect key="frame" x="26.5" y="9" width="461.5" height="14.5"/>
|
||||
<rect key="frame" x="22.5" y="13.5" width="471.5" height="14.5"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="12"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="48y-kn-7b5">
|
||||
<rect key="frame" x="492" y="1" width="30" height="30"/>
|
||||
<rect key="frame" x="498" y="6" width="30" height="30"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="30" id="I17-S0-9fp"/>
|
||||
<constraint firstAttribute="width" constant="30" id="cCe-RB-ET2"/>
|
||||
@@ -59,30 +67,30 @@
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="dVr-ZM-kkX" secondAttribute="bottom" constant="4" id="58M-yd-hhK"/>
|
||||
<constraint firstItem="PZ4-0Y-TmL" firstAttribute="centerY" secondItem="dVr-ZM-kkX" secondAttribute="centerY" id="Bu1-sl-qDk"/>
|
||||
<constraint firstAttribute="height" constant="32" id="KNn-ng-NHK"/>
|
||||
<constraint firstItem="dVr-ZM-kkX" firstAttribute="leading" secondItem="PZ4-0Y-TmL" secondAttribute="trailing" constant="4" id="RbN-mc-y2P"/>
|
||||
<constraint firstItem="48y-kn-7b5" firstAttribute="centerY" secondItem="jXI-9E-Bgl" secondAttribute="centerY" id="XbN-rm-nDw"/>
|
||||
<constraint firstItem="48y-kn-7b5" firstAttribute="leading" secondItem="dVr-ZM-kkX" secondAttribute="trailing" constant="4" id="bmi-rg-TNM"/>
|
||||
<constraint firstItem="PZ4-0Y-TmL" firstAttribute="centerY" secondItem="jXI-9E-Bgl" secondAttribute="centerY" id="f9O-vU-41g"/>
|
||||
<constraint firstItem="PZ4-0Y-TmL" firstAttribute="leading" secondItem="jXI-9E-Bgl" secondAttribute="leading" constant="12" id="mp0-tl-IIe"/>
|
||||
<constraint firstAttribute="trailing" secondItem="48y-kn-7b5" secondAttribute="trailing" constant="6" id="qPb-EI-csl"/>
|
||||
<constraint firstItem="dVr-ZM-kkX" firstAttribute="centerY" secondItem="jXI-9E-Bgl" secondAttribute="centerY" id="yb4-bq-XNb"/>
|
||||
<constraint firstItem="PZ4-0Y-TmL" firstAttribute="leading" secondItem="jXI-9E-Bgl" secondAttribute="leading" constant="8" id="mp0-tl-IIe"/>
|
||||
<constraint firstAttribute="trailing" secondItem="48y-kn-7b5" secondAttribute="trailing" id="qPb-EI-csl"/>
|
||||
<constraint firstItem="48y-kn-7b5" firstAttribute="centerY" secondItem="dVr-ZM-kkX" secondAttribute="centerY" id="z5v-Vy-6tc"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wgb-ON-N29" customClass="KeyboardGrowingTextView">
|
||||
<rect key="frame" x="4" y="33" width="520" height="4"/>
|
||||
<rect key="frame" x="5" y="33" width="518" height="4"/>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<accessibility key="accessibilityConfiguration" identifier="GrowingTextView"/>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="wgb-ON-N29" secondAttribute="trailing" constant="4" id="30f-rE-CKj"/>
|
||||
<constraint firstAttribute="trailing" secondItem="wgb-ON-N29" secondAttribute="trailing" constant="5" id="30f-rE-CKj"/>
|
||||
<constraint firstAttribute="trailing" secondItem="jXI-9E-Bgl" secondAttribute="trailing" id="3EM-Mc-ZaI"/>
|
||||
<constraint firstItem="jXI-9E-Bgl" firstAttribute="top" secondItem="QWp-NV-uh5" secondAttribute="top" id="Bp8-45-jvJ"/>
|
||||
<constraint firstItem="uH7-Q7-hpZ" firstAttribute="leading" secondItem="QWp-NV-uh5" secondAttribute="leading" id="Fli-kz-OcS"/>
|
||||
<constraint firstItem="uH7-Q7-hpZ" firstAttribute="top" secondItem="QWp-NV-uh5" secondAttribute="top" id="Gqc-ya-F1W"/>
|
||||
<constraint firstItem="wgb-ON-N29" firstAttribute="leading" secondItem="QWp-NV-uh5" secondAttribute="leading" constant="4" id="N7q-ch-iRz"/>
|
||||
<constraint firstItem="wgb-ON-N29" firstAttribute="leading" secondItem="QWp-NV-uh5" secondAttribute="leading" constant="5" id="N7q-ch-iRz"/>
|
||||
<constraint firstItem="wgb-ON-N29" firstAttribute="top" secondItem="jXI-9E-Bgl" secondAttribute="bottom" constant="1" id="UV2-Sh-peE"/>
|
||||
<constraint firstAttribute="bottom" secondItem="uH7-Q7-hpZ" secondAttribute="bottom" id="dAX-uO-gvm"/>
|
||||
<constraint firstAttribute="bottom" secondItem="wgb-ON-N29" secondAttribute="bottom" constant="-1" id="fFG-SH-Hjh"/>
|
||||
@@ -105,11 +113,14 @@
|
||||
<constraint firstItem="QWp-NV-uh5" firstAttribute="leading" secondItem="Hga-l8-Wua" secondAttribute="trailing" constant="12" id="M9f-je-3zO"/>
|
||||
<constraint firstAttribute="bottom" secondItem="QWp-NV-uh5" secondAttribute="bottom" constant="13" id="NGr-2o-sOP"/>
|
||||
<constraint firstAttribute="trailing" secondItem="G8Z-CM-tGs" secondAttribute="trailing" constant="12" id="Sua-LC-3yW"/>
|
||||
<constraint firstItem="ESv-9w-KJF" firstAttribute="leading" secondItem="Hga-l8-Wua" secondAttribute="trailing" constant="12" id="TIe-py-lFJ"/>
|
||||
<constraint firstItem="QWp-NV-uh5" firstAttribute="top" secondItem="a84-Vc-6ud" secondAttribute="top" constant="9" id="WyZ-3i-OHi"/>
|
||||
<constraint firstAttribute="bottom" secondItem="G8Z-CM-tGs" secondAttribute="bottom" constant="12" id="Yam-dS-zwr"/>
|
||||
<constraint firstAttribute="height" constant="58" id="Yjj-ua-rbe"/>
|
||||
<constraint firstAttribute="bottom" secondItem="Hga-l8-Wua" secondAttribute="bottom" constant="12" id="b0G-CY-AmP"/>
|
||||
<constraint firstAttribute="trailing" secondItem="QWp-NV-uh5" secondAttribute="trailing" constant="12" id="hXO-cY-Jgz"/>
|
||||
<constraint firstAttribute="trailing" secondItem="ESv-9w-KJF" secondAttribute="trailing" id="jCS-Tf-vxr"/>
|
||||
<constraint firstAttribute="bottom" secondItem="ESv-9w-KJF" secondAttribute="bottom" constant="12" id="v8r-ac-MKn"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
@@ -125,6 +136,7 @@
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||
<connections>
|
||||
<outlet property="actionsBar" destination="ESv-9w-KJF" id="h7H-vz-yzO"/>
|
||||
<outlet property="attachMediaButton" destination="Hga-l8-Wua" id="Osr-ek-c91"/>
|
||||
<outlet property="growingTextView" destination="wgb-ON-N29" id="nwF-uV-Ng9"/>
|
||||
<outlet property="inputContextButton" destination="48y-kn-7b5" id="yRn-1S-96w"/>
|
||||
|
||||
@@ -147,7 +147,6 @@
|
||||
self.pictureViewHeightConstraint.constant = 28;
|
||||
self.displayNameTextField.font = [UIFont systemFontOfSize:14 weight:UIFontWeightMedium];
|
||||
self.typingLabel.font = [UIFont systemFontOfSize:10];
|
||||
self.dotViewCenterXConstraint.constant = 3;
|
||||
self.dotViewCenterYConstraint.constant = -2;
|
||||
}
|
||||
else
|
||||
@@ -158,7 +157,6 @@
|
||||
self.pictureViewHeightConstraint.constant = 32;
|
||||
self.displayNameTextField.font = [UIFont systemFontOfSize:17 weight:UIFontWeightMedium];
|
||||
self.typingLabel.font = [UIFont systemFontOfSize:12];
|
||||
self.dotViewCenterXConstraint.constant = 0;
|
||||
self.dotViewCenterYConstraint.constant = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<constraint firstItem="6uH-I3-RQg" firstAttribute="leading" secondItem="LDd-c1-ILP" secondAttribute="trailing" constant="12" id="0pG-0z-gpD"/>
|
||||
<constraint firstItem="LDd-c1-ILP" firstAttribute="centerY" secondItem="BkF-x3-7fX" secondAttribute="centerY" id="33h-dC-S1U"/>
|
||||
<constraint firstAttribute="bottom" secondItem="sD9-l7-azQ" secondAttribute="bottom" id="4rX-5O-LrO"/>
|
||||
<constraint firstItem="yTB-Be-bLN" firstAttribute="centerX" secondItem="SUm-iW-DRR" secondAttribute="leading" id="7H4-kh-c2g"/>
|
||||
<constraint firstItem="yTB-Be-bLN" firstAttribute="centerX" secondItem="SUm-iW-DRR" secondAttribute="trailing" id="7H4-kh-c2g"/>
|
||||
<constraint firstItem="sD9-l7-azQ" firstAttribute="leading" secondItem="BkF-x3-7fX" secondAttribute="leading" id="AJc-Aa-sht"/>
|
||||
<constraint firstItem="SUm-iW-DRR" firstAttribute="centerY" secondItem="BkF-x3-7fX" secondAttribute="centerY" id="Blv-SJ-r6v"/>
|
||||
<constraint firstItem="Ky3-cy-HAx" firstAttribute="bottom" secondItem="LDd-c1-ILP" secondAttribute="bottom" id="HZy-1x-eyX"/>
|
||||
|
||||
Reference in New Issue
Block a user