Organize views by feature

This commit is contained in:
SBiOSoftWhare
2018-07-06 16:42:45 +02:00
parent 263c8f9246
commit fbe1264a5a
247 changed files with 1085 additions and 972 deletions
@@ -0,0 +1,85 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations 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 <MatrixKit/MatrixKit.h>
/**
`RoomExtraInfosInfoView` instance is a view used to display extra information
*/
@interface RoomActivitiesView : MXKRoomActivitiesView <UITextViewDelegate, UIGestureRecognizerDelegate>
@property (weak, nonatomic) IBOutlet UIView *separatorView;
@property (weak, nonatomic) IBOutlet UIImageView *iconImageView;
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;
@property (weak, nonatomic) IBOutlet UITextView *messageTextView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *mainHeightConstraint;
/**
Notify that some messages are not sent.
Replace the current notification if any.
@param notification the notification message to display.
@param onResendLinkPressed block called when user selects the resend link.
@param onCancelLinkPressed block called when user selects the cancel link.
@param onIconTapGesture block called when user taps on notification icon.
*/
- (void)displayUnsentMessagesNotification:(NSString*)notification withResendLink:(void (^)(void))onResendLinkPressed andCancelLink:(void (^)(void))onCancelLinkPressed andIconTapGesture:(void (^)(void))onIconTapGesture;
/**
Display network error.
Replace the current notification if any.
@param labelText the notification message
*/
- (void)displayNetworkErrorNotification:(NSString*)labelText;
/**
Display a typing notification.
Replace the current notification if any.
@param labelText the current typing message.
*/
- (void)displayTypingNotification:(NSString*)labelText;
/**
Display an ongoing conference call.
Replace the current notification if any.
@param ongoingConferenceCallPressed the block called when the user clicks on the banner.
video is YES if the user chose to join the conf in video mode.
@param ongoingConferenceCallClosePressed the block called when the user clicks on the banner close button.
nil means do not display a close button.
*/
- (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;
/**
Remove any displayed information.
*/
- (void)reset;
@end
@@ -0,0 +1,430 @@
/*
Copyright 2015 OpenMarket Ltd
Copyright 2017 Vector Creations 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 "RoomActivitiesView.h"
#import "RiotDesignValues.h"
#import <objc/runtime.h>
@interface RoomActivitiesView ()
{
// The default height as defined in the xib
CGFloat xibMainHeightConstraint;
}
@end
@implementation RoomActivitiesView
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass([RoomActivitiesView class])
bundle:[NSBundle bundleForClass:[RoomActivitiesView class]]];
}
- (CGFloat)height
{
[self checkHeight:NO];
return self.mainHeightConstraint.constant;
}
- (void)setHeight:(CGFloat)height notify:(BOOL)notify
{
if (self.mainHeightConstraint.constant != height)
{
CGFloat oldHeight = self.mainHeightConstraint.constant;
self.mainHeightConstraint.constant = height;
if (notify && self.delegate)
{
[self.delegate didChangeHeight:self oldHeight:oldHeight newHeight:self.mainHeightConstraint.constant];
}
}
}
- (void)checkHeight:(BOOL)notify
{
if (!self.messageTextView.isHidden)
{
// Compute the required height to display the text in messageTextView
CGFloat height = [self.messageTextView sizeThatFits:self.messageTextView.frame.size].height + 20; // 20 is the top and bottom margins in xib
height = MAX(xibMainHeightConstraint, height);
if (height != self.mainHeightConstraint.constant)
{
[self setHeight:height notify:notify];
}
}
else
{
// In other use case, come back to the default xib value
if (self.mainHeightConstraint.constant != xibMainHeightConstraint)
{
[self setHeight:xibMainHeightConstraint notify:notify];
}
}
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Check the required height in case on view update
// We need to delay the check in case of screen rotation to get the right screen width
dispatch_async(dispatch_get_main_queue(), ^{
[self checkHeight:YES];
});
}
- (void)awakeFromNib
{
[super awakeFromNib];
// Adjust text view
// Remove the container inset: this operation impacts only the vertical margin.
// Reset textContainer.lineFragmentPadding to remove horizontal margin.
self.messageTextView.textContainerInset = UIEdgeInsetsZero;
self.messageTextView.textContainer.lineFragmentPadding = 0;
xibMainHeightConstraint = self.mainHeightConstraint.constant;
}
#pragma mark - Override MXKView
-(void)customizeViewRendering
{
[super customizeViewRendering];
self.separatorView.backgroundColor = kRiotSecondaryBgColor;
if (self.messageLabel.textColor != kRiotColorPinkRed)
{
self.messageLabel.textColor = kRiotSecondaryTextColor;
}
}
#pragma mark -
- (void)displayUnsentMessagesNotification:(NSString*)notification withResendLink:(void (^)(void))onResendLinkPressed andCancelLink:(void (^)(void))onCancelLinkPressed andIconTapGesture:(void (^)(void))onIconTapGesture
{
[self reset];
if (onResendLinkPressed && onCancelLinkPressed)
{
NSString *resendLink = NSLocalizedStringFromTable(@"room_prompt_resend", @"Vector", nil);
NSString *cancelLink = NSLocalizedStringFromTable(@"room_prompt_cancel", @"Vector", nil);
NSString *notif = [NSString stringWithFormat:notification, resendLink, cancelLink];
NSMutableAttributedString *tappableNotif = [[NSMutableAttributedString alloc] initWithString:notif];
objc_setAssociatedObject(self.messageTextView, "onResendLinkPressed", [onResendLinkPressed copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(self.messageTextView, "onCancelLinkPressed", [onCancelLinkPressed copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
NSRange range = [notif rangeOfString:resendLink];
[tappableNotif addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:range];
[tappableNotif addAttribute:NSLinkAttributeName value:@"onResendLink" range:range];
range = [notif rangeOfString:cancelLink];
[tappableNotif addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:range];
[tappableNotif addAttribute:NSLinkAttributeName value:@"onCancelLink" range:range];
NSRange wholeString = NSMakeRange(0, tappableNotif.length);
[tappableNotif addAttribute:NSForegroundColorAttributeName value:kRiotColorPinkRed range:wholeString];
[tappableNotif addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:wholeString];
self.messageTextView.attributedText = tappableNotif;
self.messageTextView.tintColor = kRiotColorPinkRed;
self.messageTextView.hidden = NO;
self.messageTextView.backgroundColor = [UIColor clearColor];
}
else
{
self.messageLabel.text = notification;
self.messageLabel.textColor = kRiotColorPinkRed;
self.messageLabel.hidden = NO;
}
self.iconImageView.image = [UIImage imageNamed:@"error"];
self.iconImageView.hidden = NO;
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)displayNetworkErrorNotification:(NSString*)labelText
{
[self reset];
if (labelText.length)
{
self.iconImageView.image = [UIImage imageNamed:@"error"];
self.messageLabel.text = labelText;
self.messageLabel.textColor = kRiotColorPinkRed;
self.iconImageView.hidden = NO;
self.messageLabel.hidden = NO;
}
[self checkHeight:YES];
}
- (void)displayTypingNotification:(NSString*)labelText
{
[self reset];
if (labelText.length)
{
self.iconImageView.image = [UIImage imageNamed:@"typing"];
self.messageLabel.text = labelText;
self.iconImageView.hidden = NO;
self.messageLabel.hidden = NO;
}
[self checkHeight:YES];
}
- (void)displayOngoingConferenceCall:(void (^)(BOOL))onOngoingConferenceCallPressed onClosePressed:(void (^)(void))onOngoingConferenceCallClosePressed
{
[self reset];
objc_setAssociatedObject(self.messageTextView, "onOngoingConferenceCallPressed", [onOngoingConferenceCallPressed copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// Build the string to display in the banner
NSString *onGoingConferenceCall;
if (!onOngoingConferenceCallClosePressed)
{
onGoingConferenceCall = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_ongoing_conference_call", @"Vector", nil),
NSLocalizedStringFromTable(@"voice", @"Vector", nil),
NSLocalizedStringFromTable(@"video", @"Vector", nil)];
}
else
{
// Display the banner with a "Close it" string
objc_setAssociatedObject(self.messageTextView, "onOngoingConferenceCallClosePressed", [onOngoingConferenceCallClosePressed copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
onGoingConferenceCall = [NSString stringWithFormat:NSLocalizedStringFromTable(@"room_ongoing_conference_call_with_close", @"Vector", nil),
NSLocalizedStringFromTable(@"voice", @"Vector", nil),
NSLocalizedStringFromTable(@"video", @"Vector", nil),
NSLocalizedStringFromTable(@"room_ongoing_conference_call_close", @"Vector", nil)];
}
NSMutableAttributedString *onGoingConferenceCallAttibutedString = [[NSMutableAttributedString alloc] initWithString:onGoingConferenceCall];
// Add a link on the "voice" string
NSRange voiceRange = [onGoingConferenceCall rangeOfString:NSLocalizedStringFromTable(@"voice", @"Vector", nil)];
[onGoingConferenceCallAttibutedString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:voiceRange];
[onGoingConferenceCallAttibutedString addAttribute:NSLinkAttributeName value:@"onOngoingConferenceCallWithVoicePressed" range:voiceRange];
// Add a link on the "video" string
NSRange videoRange = [onGoingConferenceCall rangeOfString:NSLocalizedStringFromTable(@"video", @"Vector", nil)];
[onGoingConferenceCallAttibutedString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:videoRange];
[onGoingConferenceCallAttibutedString addAttribute:NSLinkAttributeName value:@"onOngoingConferenceCallWithVideoPressed" range:videoRange];
// Add a link on the "Close" string
if (onOngoingConferenceCallClosePressed)
{
NSRange closeRange = [onGoingConferenceCall rangeOfString:NSLocalizedStringFromTable(@"room_ongoing_conference_call_close", @"Vector", nil)];
[onGoingConferenceCallAttibutedString addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:closeRange];
[onGoingConferenceCallAttibutedString addAttribute:NSLinkAttributeName value:@"onOngoingConferenceCallClosePressed" range:closeRange];
}
// Display the string in white on pink red
NSRange wholeString = NSMakeRange(0, onGoingConferenceCallAttibutedString.length);
[onGoingConferenceCallAttibutedString addAttribute:NSForegroundColorAttributeName value:kRiotPrimaryBgColor range:wholeString];
[onGoingConferenceCallAttibutedString addAttribute:NSBackgroundColorAttributeName value:kRiotColorPinkRed range:wholeString];
[onGoingConferenceCallAttibutedString addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:15] range:wholeString];
self.messageTextView.attributedText = onGoingConferenceCallAttibutedString;
self.messageTextView.tintColor = kRiotPrimaryBgColor;
self.messageTextView.hidden = NO;
self.backgroundColor = kRiotColorPinkRed;
self.messageTextView.backgroundColor = kRiotColorPinkRed;
// Hide the separator to display correctly the red pink conf call banner
self.separatorView.hidden = YES;
[self checkHeight:YES];
}
- (void)displayScrollToBottomIcon:(NSUInteger)newMessagesCount onIconTapGesture:(void (^)(void))onIconTapGesture
{
if (newMessagesCount)
{
[self reset];
self.iconImageView.image = [UIImage imageNamed:@"newmessages"];
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 = kRiotColorPinkRed;
self.messageLabel.hidden = NO;
}
else
{
// We keep the current message if any
[self resetIcon];
self.iconImageView.image = [UIImage imageNamed:@"scrolldown"];
}
self.iconImageView.hidden = NO;
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)reset
{
self.separatorView.hidden = NO;
self.backgroundColor = UIColor.clearColor;
[self resetIcon];
[self resetMessage];
}
- (void)resetIcon
{
self.iconImageView.hidden = YES;
// Remove all gesture recognizers
while (self.iconImageView.gestureRecognizers.count)
{
[self.iconImageView removeGestureRecognizer:self.iconImageView.gestureRecognizers[0]];
}
self.iconImageView.userInteractionEnabled = NO;
objc_removeAssociatedObjects(self.iconImageView);
[self checkHeight:YES];
}
- (void)resetMessage
{
self.messageLabel.hidden = YES;
[self.messageTextView resignFirstResponder];
self.messageTextView.hidden = YES;
self.messageLabel.textColor = kRiotSecondaryTextColor;
objc_removeAssociatedObjects(self.messageTextView);
}
#pragma mark - UITextViewDelegate
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
if ([[URL absoluteString] isEqualToString:@"onResendLink"])
{
void (^onResendLinkPressed)(void) = objc_getAssociatedObject(self.messageTextView, "onResendLinkPressed");
if (onResendLinkPressed)
{
onResendLinkPressed ();
}
return NO;
}
else if ([[URL absoluteString] isEqualToString:@"onCancelLink"])
{
void (^onCancelLinkPressed)(void) = objc_getAssociatedObject(self.messageTextView, "onCancelLinkPressed");
if (onCancelLinkPressed)
{
onCancelLinkPressed ();
}
return NO;
}
else if ([[URL absoluteString] isEqualToString:@"onOngoingConferenceCallWithVoicePressed"])
{
void (^onOngoingConferenceCallPressed)(BOOL) = objc_getAssociatedObject(self.messageTextView, "onOngoingConferenceCallPressed");
if (onOngoingConferenceCallPressed)
{
onOngoingConferenceCallPressed(NO);
}
return NO;
}
else if ([[URL absoluteString] isEqualToString:@"onOngoingConferenceCallWithVideoPressed"])
{
void (^onOngoingConferenceCallPressed)(BOOL) = objc_getAssociatedObject(self.messageTextView, "onOngoingConferenceCallPressed");
if (onOngoingConferenceCallPressed)
{
onOngoingConferenceCallPressed(YES);
}
return NO;
}
else if ([[URL absoluteString] isEqualToString:@"onOngoingConferenceCallClosePressed"])
{
void (^onOngoingConferenceCallClosePressed)(BOOL) = objc_getAssociatedObject(self.messageTextView, "onOngoingConferenceCallClosePressed");
if (onOngoingConferenceCallClosePressed)
{
onOngoingConferenceCallClosePressed(YES);
}
return NO;
} return YES;
}
#pragma mark - UIGestureRecognizerDelegate
- (void)onIconTap:(UITapGestureRecognizer*)sender
{
void (^onIconTapGesture)(void) = objc_getAssociatedObject(self.iconImageView, "onIconTapGesture");
if (onIconTapGesture)
{
onIconTapGesture ();
}
}
@end
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<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"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="RoomActivitiesView">
<rect key="frame" x="0.0" y="0.0" width="600" height="53"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qhJ-5H-64e" userLabel="Container">
<rect key="frame" x="0.0" y="0.0" width="600" height="53"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="1Mq-77-vvo" userLabel="Separator View">
<rect key="frame" x="13" y="0.0" width="577" height="1"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="jIT-QS-Muj"/>
</constraints>
</view>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="typing.png" translatesAutoresizingMaskIntoConstraints="NO" id="d6j-oN-9uA">
<rect key="frame" x="13" y="11.5" width="30" height="30"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomActivitiesViewIconImageView"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="657-fV-gDE"/>
<constraint firstAttribute="width" constant="30" id="vxL-QJ-z0p"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="wordWrap" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7bS-1u-GUX" userLabel="Message Label">
<rect key="frame" x="56" y="5.5" width="514" height="42"/>
<accessibility key="accessibilityConfiguration" identifier="RoomActivitiesViewMessageLabel"/>
<constraints>
<constraint firstAttribute="height" constant="42" id="PVB-be-euJ"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<textView hidden="YES" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" bounces="NO" scrollEnabled="NO" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="6ND-Cq-ABj">
<rect key="frame" x="56" y="10" width="514" height="33"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomActivitiesViewMessageTextView"/>
<string key="text">Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda.</string>
<color key="textColor" red="1" green="0.119521145" blue="0.2069467156" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
<connections>
<outlet property="delegate" destination="iN0-l3-epB" id="ZAk-sC-QpQ"/>
</connections>
</textView>
</subviews>
<constraints>
<constraint firstItem="1Mq-77-vvo" firstAttribute="leading" secondItem="qhJ-5H-64e" secondAttribute="leading" constant="13" id="2S8-TD-jHO"/>
<constraint firstItem="7bS-1u-GUX" firstAttribute="leading" secondItem="d6j-oN-9uA" secondAttribute="trailing" constant="13" id="6Js-Lq-pKz"/>
<constraint firstItem="7bS-1u-GUX" firstAttribute="centerY" secondItem="d6j-oN-9uA" secondAttribute="centerY" id="BIB-uG-AY7"/>
<constraint firstAttribute="trailing" secondItem="1Mq-77-vvo" secondAttribute="trailing" constant="10" id="YBp-az-maq"/>
<constraint firstItem="d6j-oN-9uA" firstAttribute="leading" secondItem="qhJ-5H-64e" secondAttribute="leading" constant="13" id="YYC-Q1-IoC"/>
<constraint firstItem="6ND-Cq-ABj" firstAttribute="leading" secondItem="d6j-oN-9uA" secondAttribute="trailing" constant="13" id="ZdK-4Z-Yfz"/>
<constraint firstItem="6ND-Cq-ABj" firstAttribute="top" secondItem="qhJ-5H-64e" secondAttribute="top" constant="10" id="j7I-pC-7fV"/>
<constraint firstAttribute="bottom" secondItem="6ND-Cq-ABj" secondAttribute="bottom" constant="10" id="m0j-16-mJw"/>
<constraint firstItem="d6j-oN-9uA" firstAttribute="centerY" secondItem="qhJ-5H-64e" secondAttribute="centerY" id="rEU-px-J59"/>
<constraint firstItem="1Mq-77-vvo" firstAttribute="top" secondItem="qhJ-5H-64e" secondAttribute="top" id="stG-o2-SK4"/>
<constraint firstAttribute="trailing" secondItem="7bS-1u-GUX" secondAttribute="trailing" constant="30" id="tCW-EI-6Yt"/>
<constraint firstItem="6ND-Cq-ABj" firstAttribute="centerY" secondItem="d6j-oN-9uA" secondAttribute="centerY" id="vF4-wk-Jqe"/>
<constraint firstAttribute="height" constant="53" id="xPK-Yw-hQ9"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomExtrasInfosView"/>
<constraints>
<constraint firstItem="qhJ-5H-64e" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" id="4o2-V9-a4L"/>
<constraint firstAttribute="trailing" secondItem="6ND-Cq-ABj" secondAttribute="trailing" constant="30" id="82b-uO-ua7"/>
<constraint firstItem="qhJ-5H-64e" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="wDi-7P-36c"/>
<constraint firstItem="qhJ-5H-64e" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="wsu-Zi-OE6"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<connections>
<outlet property="iconImageView" destination="d6j-oN-9uA" id="Qhw-fw-uGc"/>
<outlet property="mainHeightConstraint" destination="xPK-Yw-hQ9" id="dJ5-pI-KyT"/>
<outlet property="messageLabel" destination="7bS-1u-GUX" id="5c1-hT-y49"/>
<outlet property="messageTextView" destination="6ND-Cq-ABj" id="xWk-ga-9xS"/>
<outlet property="separatorView" destination="1Mq-77-vvo" id="8fc-AO-8hF"/>
</connections>
</view>
</objects>
<resources>
<image name="typing.png" width="31" height="30"/>
</resources>
</document>