Composer update - UI enhancements

- Composer height =58px - Frame = 42px
- Replace current scroll to bottom implementation with a scroll to Bottom FAB on both themes
- The text inside the composer frame should be centered
- The padding between the "reveal plus" button, composer frame and Left + Right sides should be at equal distance on default mode
- Verify that the "Send a message..." String matches with the colour indicated on Figma.
- The padding between each component (buttons and composer frame) should be at equal distance on default mode. E.g : It should be at 12px for each gap.
- The input text jumps down when users start typing. It should be centered at all times.
- Remove the Scroll bar in the text frame.
- DARK THEME
This commit is contained in:
Gil Eluard 2021-03-20 21:31:17 +01:00
parent 55f95c72a5
commit d561ef472b
25 changed files with 167 additions and 115 deletions

View file

@ -19,8 +19,5 @@
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 B

After

Width:  |  Height:  |  Size: 588 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "scrolldown_dark.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "scrolldown_dark@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "scrolldown_dark@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 776 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -19,5 +19,8 @@
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "upload_icon_dark.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "upload_icon_dark@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "upload_icon_dark@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 823 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -102,6 +102,7 @@ internal enum Asset {
internal static let errorMessageTick = ImageAsset(name: "error_message_tick")
internal static let roomActivitiesRetry = ImageAsset(name: "room_activities_retry")
internal static let scrolldown = ImageAsset(name: "scrolldown")
internal static let scrolldownDark = ImageAsset(name: "scrolldown_dark")
internal static let sendingMessageTick = ImageAsset(name: "sending_message_tick")
internal static let sentMessageTick = ImageAsset(name: "sent_message_tick")
internal static let typing = ImageAsset(name: "typing")
@ -114,6 +115,7 @@ internal enum Asset {
internal static let inputTextBackground = ImageAsset(name: "input_text_background")
internal static let sendIcon = ImageAsset(name: "send_icon")
internal static let uploadIcon = ImageAsset(name: "upload_icon")
internal static let uploadIconDark = ImageAsset(name: "upload_icon_dark")
internal static let videoCall = ImageAsset(name: "video_call")
internal static let voiceCallHangonIcon = ImageAsset(name: "voice_call_hangon_icon")
internal static let voiceCallHangupIcon = ImageAsset(name: "voice_call_hangup_icon")

View file

@ -70,6 +70,7 @@ import UIKit
// MARK: - Appearance and style
var roomInputTextBorder: UIColor { get }
/// Status bar style to use
var statusBarStyle: UIStatusBarStyle { get }

View file

@ -52,6 +52,8 @@ class DarkTheme: NSObject, Theme {
var noticeSecondaryColor: UIColor = UIColor(rgb: 0x61708B)
var warningColor: UIColor = UIColor(rgb: 0xFF4B55)
var roomInputTextBorder: UIColor = UIColor(rgb: 0x8D97A5).withAlphaComponent(0.2)
var avatarColors: [UIColor] = [
UIColor(rgb: 0x03B381),

View file

@ -52,8 +52,8 @@ class DefaultTheme: NSObject, Theme {
var noticeSecondaryColor: UIColor = UIColor(rgb: 0x61708B)
var warningColor: UIColor = UIColor(rgb: 0xFF4B55)
var messageTickColor: UIColor = UIColor(rgb: 0xC1C6CD)
var roomInputTextBorder: UIColor = UIColor(rgb: 0xE3E8F0)
var avatarColors: [UIColor] = [
UIColor(rgb: 0x03B381),

View file

@ -40,7 +40,7 @@ class BadgeLabel: UILabel {
}
}
@IBInspectable var padding: CGSize = CGSize(width: 10, height: 2) {
@IBInspectable var padding: CGSize = CGSize(width: 10, height: 3) {
didSet {
invalidateIntrinsicContentSize()
}

View file

@ -27,6 +27,8 @@
#import "UIViewController+RiotSearch.h"
@class BadgeLabel;
/**
Notification string used to indicate call tile tapped in a room. Notification object will be the `RoomBubbleCellData` object.
*/
@ -47,6 +49,8 @@ extern NSNotificationName const RoomCallTileTappedNotification;
@property (weak, nonatomic) IBOutlet UIButton *resetReadMarkerButton;
@property (weak, nonatomic) IBOutlet UIView *jumpToLastUnreadBannerSeparatorView;
@property (weak, nonatomic) IBOutlet UIVisualEffectView *inputBackgroundView;
@property (weak, nonatomic) IBOutlet UIButton *scrollToBottomButton;
@property (weak, nonatomic) IBOutlet BadgeLabel *scrollToBottomBadgeLabel;
/**
Preview data for a room invitation received by email, or a link to a room.
@ -73,5 +77,7 @@ extern NSNotificationName const RoomCallTileTappedNotification;
*/
- (IBAction)onButtonPressed:(id)sender;
- (IBAction)scrollToBottomAction:(id)sender;
@end

View file

@ -227,6 +227,7 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
@property (nonatomic, strong) RoomInfoCoordinatorBridgePresenter *roomInfoCoordinatorBridgePresenter;
@property (nonatomic, strong) CustomSizedPresentationController *customSizedPresentationController;
@property (nonatomic, getter=isActivitiesViewExpanded) BOOL activitiesViewExpanded;
@property (nonatomic, getter=isScrollToBottomHidden) BOOL scrollToBottomHidden;
@end
@ -291,7 +292,7 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
formattedBodyParser = [FormattedBodyParser new];
_showMissedDiscussionsBadge = YES;
_scrollToBottomHidden = YES;
// Listen to the event sent state changes
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(eventDidChangeSentState:) name:kMXEventDidChangeSentStateNotification object:nil];
@ -409,15 +410,6 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
}];
[self userInterfaceThemeDidChange];
if ([ThemeService.shared.themeId isEqualToString:@"light"])
{
self.inputBackgroundView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
}
else if ([ThemeService.shared.themeId isEqualToString:@"dark"] || [ThemeService.shared.themeId isEqualToString:@"black"])
{
self.inputBackgroundView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
}
}
- (void)userInterfaceThemeDidChange
@ -468,6 +460,27 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
[self.bubblesTableView reloadData];
}
self.scrollToBottomButton.layer.shadowColor = [UIColor blackColor].CGColor;
self.scrollToBottomButton.layer.shadowOpacity = 0.2;
self.scrollToBottomButton.layer.shadowRadius = 6;
self.scrollToBottomButton.layer.shadowOffset = CGSizeMake(0, 4);
if ([ThemeService.shared.themeId isEqualToString:@"light"])
{
self.inputBackgroundView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
[self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown"] forState:UIControlStateNormal];
}
else if ([ThemeService.shared.themeId isEqualToString:@"dark"] || [ThemeService.shared.themeId isEqualToString:@"black"])
{
self.inputBackgroundView.effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
[self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown_dark"] forState:UIControlStateNormal];
}
else if (@available(iOS 12.0, *) && ThemeService.shared.theme.userInterfaceStyle == UIUserInterfaceStyleDark) {
[self.scrollToBottomButton setImage:[UIImage imageNamed:@"scrolldown_dark"] forState:UIControlStateNormal];
}
self.scrollToBottomBadgeLabel.badgeColor = ThemeService.shared.theme.tintColor;
[self setNeedsStatusBarAppearanceUpdate];
}
@ -1276,7 +1289,7 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
[super destroy];
}
#pragma mark -
#pragma mark - Properties
-(void)setActivitiesViewExpanded:(BOOL)activitiesViewExpanded
{
@ -1294,6 +1307,19 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
missedDiscussionsBadgeLabel.hidden = !showMissedDiscussionsBadge;
}
- (void)setScrollToBottomHidden:(BOOL)scrollToBottomHidden
{
if (_scrollToBottomHidden != scrollToBottomHidden)
{
_scrollToBottomHidden = scrollToBottomHidden;
}
[UIView animateWithDuration:.2 animations:^{
self.scrollToBottomBadgeLabel.alpha = (scrollToBottomHidden || !self.scrollToBottomBadgeLabel.text) ? 0 : 1;
self.scrollToBottomButton.alpha = scrollToBottomHidden ? 0 : 1;
}];
}
#pragma mark - Internals
- (void)forceLayoutRefresh
@ -3647,6 +3673,11 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
[widgetPicker showInViewController:self];
}
- (void)scrollToBottomAction:(id)sender
{
[self goBackToLive];
}
- (IBAction)onButtonPressed:(id)sender
{
if (sender == self.jumpToLastUnreadButton)
@ -4360,15 +4391,12 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
// Retrieve the unread messages count
NSUInteger unreadCount = self.roomDataSource.room.summary.localUnreadEventCount;
self.activitiesViewExpanded = YES;
[roomActivitiesView displayScrollToBottomIcon:unreadCount onIconTapGesture:^{
[self goBackToLive];
}];
self.scrollToBottomBadgeLabel.text = unreadCount ? [NSString stringWithFormat:@"%lu", unreadCount] : nil;
self.scrollToBottomHidden = NO;
}
else if (serverNotices.usageLimit && serverNotices.usageLimit.isServerNoticeUsageLimit)
{
self.scrollToBottomHidden = YES;
self.activitiesViewExpanded = YES;
[roomActivitiesView showResourceUsageLimitNotice:serverNotices.usageLimit onAdminContactTapped:^(NSURL *adminContactURL) {
[[UIApplication sharedApplication] vc_open:adminContactURL completionHandler:^(BOOL success) {
@ -4381,6 +4409,7 @@ NSNotificationName const RoomCallTileTappedNotification = @"RoomCallTileTappedNo
}
else
{
self.scrollToBottomHidden = YES;
self.activitiesViewExpanded = NO;
[self refreshTypingNotification];
}

View file

@ -29,6 +29,8 @@
<outlet property="roomInputToolbarContainer" destination="nLd-BP-JAE" id="1dp-P1-0js"/>
<outlet property="roomInputToolbarContainerBottomConstraint" destination="omU-sm-3bK" id="qaT-Ej-BdE"/>
<outlet property="roomInputToolbarContainerHeightConstraint" destination="5eD-Fm-RDb" id="6ny-5w-1UA"/>
<outlet property="scrollToBottomBadgeLabel" destination="QHs-rM-UU8" id="wk7-PQ-9Jm"/>
<outlet property="scrollToBottomButton" destination="Ih9-EU-BOU" id="Wwg-gS-Sfp"/>
<outlet property="view" destination="iN0-l3-epB" id="ieV-u7-rXU"/>
</connections>
</placeholder>
@ -130,6 +132,19 @@
<constraint firstItem="ISb-UT-u0O" firstAttribute="centerY" secondItem="Vlz-UJ-Jz8" secondAttribute="centerY" id="w7t-WC-VjP"/>
</constraints>
</view>
<button opaque="NO" alpha="0.0" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ih9-EU-BOU" userLabel="scroll Button">
<rect key="frame" x="327" y="570" width="32" height="32"/>
<state key="normal" image="scrolldown"/>
<connections>
<action selector="scrollToBottomAction:" destination="-1" eventType="touchUpInside" id="TOf-aY-J6a"/>
</connections>
</button>
<label opaque="NO" userInteractionEnabled="NO" alpha="0.0" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QHs-rM-UU8" userLabel="scroll badge" customClass="BadgeLabel" customModule="Riot" customModuleProvider="target">
<rect key="frame" x="334" y="562.5" width="18" height="15.5"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="11"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="XX4-n6-hCm" userLabel="Activities Container">
<rect key="frame" x="0.0" y="626" width="375" height="0.0"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
@ -158,12 +173,16 @@
<constraint firstAttribute="bottom" secondItem="BGD-sd-SQR" secondAttribute="bottom" constant="41" id="1SD-y2-oTg"/>
<constraint firstItem="S6r-bo-jxw" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="5eM-eJ-khq"/>
<constraint firstItem="lPR-zi-UZr" firstAttribute="trailing" secondItem="QpJ-1u-4ii" secondAttribute="trailing" id="6no-fN-liL"/>
<constraint firstItem="QpJ-1u-4ii" firstAttribute="trailing" secondItem="Ih9-EU-BOU" secondAttribute="trailing" constant="16" id="6rq-lR-0sB"/>
<constraint firstItem="54r-18-K1g" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="7Ft-EV-Br0"/>
<constraint firstItem="gt1-EO-UVY" firstAttribute="leading" secondItem="QpJ-1u-4ii" secondAttribute="leading" id="8Ff-Ot-h3F"/>
<constraint firstItem="S6r-bo-jxw" firstAttribute="leading" secondItem="QpJ-1u-4ii" secondAttribute="leading" id="Bcq-e4-B0D"/>
<constraint firstItem="BGD-sd-SQR" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="ECb-mP-EOG"/>
<constraint firstAttribute="trailing" secondItem="BGD-sd-SQR" secondAttribute="trailing" id="EGD-cX-OGq"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="top" secondItem="Ih9-EU-BOU" secondAttribute="bottom" constant="24" id="GUp-ZU-6h3"/>
<constraint firstItem="lPR-zi-UZr" firstAttribute="bottom" secondItem="iN0-l3-epB" secondAttribute="bottom" id="HJy-rU-H5H"/>
<constraint firstItem="QHs-rM-UU8" firstAttribute="centerX" secondItem="Ih9-EU-BOU" secondAttribute="centerX" id="K8X-wJ-hkh"/>
<constraint firstItem="QHs-rM-UU8" firstAttribute="centerY" secondItem="Ih9-EU-BOU" secondAttribute="top" id="KL4-OU-cP6"/>
<constraint firstItem="gt1-EO-UVY" firstAttribute="trailing" secondItem="QpJ-1u-4ii" secondAttribute="trailing" id="L9A-P5-xeT"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="leading" secondItem="QpJ-1u-4ii" secondAttribute="leading" id="Os4-cU-eQb"/>
<constraint firstItem="XX4-n6-hCm" firstAttribute="bottom" secondItem="nLd-BP-JAE" secondAttribute="top" id="QO8-nF-xys"/>
@ -184,8 +203,14 @@
<point key="canvasLocation" x="136.80000000000001" y="152.47376311844079"/>
</view>
</objects>
<designables>
<designable name="QHs-rM-UU8">
<size key="intrinsicContentSize" width="17.5" height="15.5"/>
</designable>
</designables>
<resources>
<image name="cancel" width="20" height="20"/>
<image name="scrolldown" width="32" height="32"/>
<image name="scrollup" width="30" height="30"/>
</resources>
</document>

View file

@ -73,16 +73,6 @@
*/
- (void)displayOngoingConferenceCall:(void (^)(BOOL video))ongoingConferenceCallPressed onClosePressed:(void (^)(void))ongoingConferenceCallClosePressed;
/**
Display a "scroll to bottom" icon.
Replace the current notification if any.
@param newMessagesCount the count of the unread messages.
@param onIconTapGesture block called when user taps on notification icon.
*/
- (void)displayScrollToBottomIcon:(NSUInteger)newMessagesCount onIconTapGesture:(void (^)(void))onIconTapGesture;
/**
Notify that the a room is obsolete and a replacement room is available.

View file

@ -268,62 +268,6 @@
[self checkHeight:YES];
}
- (void)displayScrollToBottomIcon:(NSUInteger)newMessagesCount onIconTapGesture:(void (^)(void))onIconTapGesture
{
if (newMessagesCount)
{
[self reset];
self.iconImageView.image = [UIImage imageNamed:@"scrolldown"];
self.iconImageView.tintColor = ThemeService.shared.theme.noticeColor;
NSString *notification;
if (newMessagesCount > 1)
{
notification = NSLocalizedStringFromTable(@"room_new_messages_notification", @"Vector", nil);
}
else
{
notification = NSLocalizedStringFromTable(@"room_new_message_notification", @"Vector", nil);
}
self.messageLabel.text = [NSString stringWithFormat:notification, newMessagesCount];
self.messageLabel.textColor = ThemeService.shared.theme.warningColor;
self.messageLabel.hidden = NO;
}
else
{
self.unsentMessagesContentView.hidden = YES;
// We keep the current message if any
[self resetIcon];
self.messageLabel.text = nil;
self.iconImageView.image = [UIImage imageNamed:@"scrolldown"];
self.iconImageView.tintColor = ThemeService.shared.theme.textPrimaryColor;
}
self.iconImageView.hidden = NO;
// Make VoiceOver consider it as a button
self.iconImageView.accessibilityLabel = NSLocalizedStringFromTable(@"room_accessiblity_scroll_to_bottom", @"Vector", nil);
self.iconImageView.isAccessibilityElement = YES;
self.iconImageView.accessibilityTraits = UIAccessibilityTraitButton;
if (onIconTapGesture)
{
objc_setAssociatedObject(self.iconImageView, "onIconTapGesture", [onIconTapGesture copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// Listen to icon tap
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onIconTap:)];
[tapGesture setNumberOfTouchesRequired:1];
[tapGesture setNumberOfTapsRequired:1];
[tapGesture setDelegate:self];
[self.iconImageView addGestureRecognizer:tapGesture];
self.iconImageView.userInteractionEnabled = YES;
}
[self checkHeight:YES];
}
- (void)displayRoomReplacementWithRoomLinkTappedHandler:(void (^)(void))onRoomReplacementLinkTapped
{
[self reset];

View file

@ -85,7 +85,7 @@
growingTextView.font = [UIFont systemFontOfSize:15];
growingTextView.textColor = ThemeService.shared.theme.textPrimaryColor;
growingTextView.tintColor = ThemeService.shared.theme.tintColor;
growingTextView.placeholderColor = ThemeService.shared.theme.textTertiaryColor;
growingTextView.internalTextView.showsVerticalScrollIndicator = NO;
growingTextView.internalTextView.keyboardAppearance = ThemeService.shared.theme.keyboardAppearance;
@ -100,6 +100,19 @@
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];
}
}
#pragma mark -
@ -187,21 +200,15 @@
if (self.rightInputToolbarButton.isEnabled && !self.rightInputToolbarButton.alpha)
{
[UIView animateWithDuration:.4 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:8 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.rightInputToolbarButton.alpha = 1;
self.messageComposerContainerTrailingConstraint.constant = self.frame.size.width - self.rightInputToolbarButton.frame.origin.x + 12;
[self layoutIfNeeded];
} completion:^(BOOL finished) {
}];
self.rightInputToolbarButton.alpha = 1;
self.messageComposerContainerTrailingConstraint.constant = self.frame.size.width - self.rightInputToolbarButton.frame.origin.x + 12;
[self layoutIfNeeded];
}
else if (!self.rightInputToolbarButton.isEnabled && self.rightInputToolbarButton.alpha)
{
[UIView animateWithDuration:.4 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:8 options:UIViewAnimationOptionCurveEaseIn animations:^{
self.rightInputToolbarButton.alpha = 0;
self.messageComposerContainerTrailingConstraint.constant = 12;
[self layoutIfNeeded];
} completion:^(BOOL finished) {
}];
self.rightInputToolbarButton.alpha = 0;
self.messageComposerContainerTrailingConstraint.constant = 12;
[self layoutIfNeeded];
}
}

View file

@ -14,13 +14,13 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="a84-Vc-6ud" userLabel="MainToolBar View">
<rect key="frame" x="0.0" y="0.0" width="600" height="60"/>
<rect key="frame" x="0.0" y="2" width="600" height="58"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Hga-l8-Wua" userLabel="attach Button">
<rect key="frame" x="12" y="12" width="46" height="36"/>
<rect key="frame" x="12" y="10" width="36" height="36"/>
<accessibility key="accessibilityConfiguration" identifier="AttachButton"/>
<constraints>
<constraint firstAttribute="width" constant="46" id="O2T-T8-EjV"/>
<constraint firstAttribute="width" constant="36" id="O2T-T8-EjV"/>
</constraints>
<state key="normal" image="upload_icon"/>
<connections>
@ -28,13 +28,13 @@
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QWp-NV-uh5" userLabel="Message Composer Container">
<rect key="frame" x="70" y="10" width="518" height="40"/>
<rect key="frame" x="60" y="9" width="528" height="36"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="input_text_background" translatesAutoresizingMaskIntoConstraints="NO" id="uH7-Q7-hpZ">
<rect key="frame" x="0.0" y="0.0" width="518" height="42"/>
<rect key="frame" x="0.0" y="0.0" width="528" height="38"/>
</imageView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="wgb-ON-N29" customClass="KeyboardGrowingTextView">
<rect key="frame" x="4" y="1" width="510" height="40"/>
<rect key="frame" x="4" y="1" width="520" height="36"/>
<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>
@ -52,7 +52,7 @@
</constraints>
</view>
<button opaque="NO" alpha="0.0" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="G8Z-CM-tGs" userLabel="send Button">
<rect key="frame" x="552" y="12" width="36" height="36"/>
<rect key="frame" x="552" y="10" width="36" height="36"/>
<accessibility key="accessibilityConfiguration" identifier="SendButton"/>
<state key="normal" image="send_icon"/>
<connections>
@ -61,15 +61,15 @@
</button>
</subviews>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="60" id="1FO-iu-urG"/>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="58" id="1FO-iu-urG"/>
<constraint firstItem="Hga-l8-Wua" firstAttribute="leading" secondItem="a84-Vc-6ud" secondAttribute="leading" constant="12" id="31r-fn-347"/>
<constraint firstItem="G8Z-CM-tGs" firstAttribute="centerY" secondItem="a84-Vc-6ud" secondAttribute="centerY" id="Fsw-LO-vgm"/>
<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="10" id="NGr-2o-sOP"/>
<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="QWp-NV-uh5" firstAttribute="top" secondItem="a84-Vc-6ud" secondAttribute="top" constant="10" id="WyZ-3i-OHi"/>
<constraint firstItem="Hga-l8-Wua" firstAttribute="centerY" secondItem="a84-Vc-6ud" secondAttribute="centerY" id="YND-k2-HMH"/>
<constraint firstAttribute="height" constant="60" id="Yjj-ua-rbe"/>
<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"/>
</constraints>
</view>