Group details: Add Rooms page

https://github.com/vector-im/riot-meta/issues/117
This commit is contained in:
Giom Foret 2017-12-31 12:52:22 +01:00
parent 07f331c160
commit 0797524a16
11 changed files with 1011 additions and 22 deletions

View file

@ -589,6 +589,10 @@
F0E05A451EA0F9EB004B83FB /* tab_rooms.png in Resources */ = {isa = PBXBuildFile; fileRef = F0E05A2D1EA0F9EB004B83FB /* tab_rooms.png */; };
F0E05A461EA0F9EB004B83FB /* tab_rooms@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0E05A2E1EA0F9EB004B83FB /* tab_rooms@2x.png */; };
F0E05A471EA0F9EB004B83FB /* tab_rooms@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = F0E05A2F1EA0F9EB004B83FB /* tab_rooms@3x.png */; };
F0E5D90E1FF6DDCF00560D7F /* GroupRoomsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F0E5D90C1FF6DDCF00560D7F /* GroupRoomsViewController.m */; };
F0E5D90F1FF6DDCF00560D7F /* GroupRoomsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0E5D90D1FF6DDCF00560D7F /* GroupRoomsViewController.xib */; };
F0E5D9131FF6FF3F00560D7F /* GroupRoomTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = F0E5D9101FF6FF3E00560D7F /* GroupRoomTableViewCell.m */; };
F0E5D9141FF6FF3F00560D7F /* GroupRoomTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F0E5D9111FF6FF3F00560D7F /* GroupRoomTableViewCell.xib */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -1380,6 +1384,12 @@
F0E05A2D1EA0F9EB004B83FB /* tab_rooms.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tab_rooms.png; sourceTree = "<group>"; };
F0E05A2E1EA0F9EB004B83FB /* tab_rooms@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tab_rooms@2x.png"; sourceTree = "<group>"; };
F0E05A2F1EA0F9EB004B83FB /* tab_rooms@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "tab_rooms@3x.png"; sourceTree = "<group>"; };
F0E5D90B1FF6DDCF00560D7F /* GroupRoomsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupRoomsViewController.h; sourceTree = "<group>"; };
F0E5D90C1FF6DDCF00560D7F /* GroupRoomsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupRoomsViewController.m; sourceTree = "<group>"; };
F0E5D90D1FF6DDCF00560D7F /* GroupRoomsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GroupRoomsViewController.xib; sourceTree = "<group>"; };
F0E5D9101FF6FF3E00560D7F /* GroupRoomTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupRoomTableViewCell.m; sourceTree = "<group>"; };
F0E5D9111FF6FF3F00560D7F /* GroupRoomTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = GroupRoomTableViewCell.xib; sourceTree = "<group>"; };
F0E5D9121FF6FF3F00560D7F /* GroupRoomTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupRoomTableViewCell.h; sourceTree = "<group>"; };
F546BCBBB9BBEE67DB28878A /* Pods-RiotPods-Riot.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RiotPods-Riot.release.xcconfig"; path = "Pods/Target Support Files/Pods-RiotPods-Riot/Pods-RiotPods-Riot.release.xcconfig"; sourceTree = "<group>"; };
FD9D0BDE9232898950554DD5 /* libPods-Riot.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Riot.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@ -2115,6 +2125,9 @@
F083BC191E7009EC00A9B29C /* ViewController */ = {
isa = PBXGroup;
children = (
F0E5D90B1FF6DDCF00560D7F /* GroupRoomsViewController.h */,
F0E5D90C1FF6DDCF00560D7F /* GroupRoomsViewController.m */,
F0E5D90D1FF6DDCF00560D7F /* GroupRoomsViewController.xib */,
F046DC7C1FE1A40F00E3DAF0 /* GroupParticipantsViewController.h */,
F046DC7B1FE1A40F00E3DAF0 /* GroupParticipantsViewController.m */,
F046DC7D1FE1A40F00E3DAF0 /* GroupParticipantsViewController.xib */,
@ -2459,6 +2472,9 @@
F083BCDC1E7009EC00A9B29C /* RoomList */ = {
isa = PBXGroup;
children = (
F0E5D9121FF6FF3F00560D7F /* GroupRoomTableViewCell.h */,
F0E5D9101FF6FF3E00560D7F /* GroupRoomTableViewCell.m */,
F0E5D9111FF6FF3F00560D7F /* GroupRoomTableViewCell.xib */,
F075BED31EBB169C00A7B68A /* RoomCollectionViewCell.h */,
F075BED41EBB169C00A7B68A /* RoomCollectionViewCell.m */,
F075BED51EBB169C00A7B68A /* RoomCollectionViewCell.xib */,
@ -3048,6 +3064,7 @@
F083BDDA1E7009ED00A9B29C /* typing.png in Resources */,
F083BE831E7009ED00A9B29C /* RecentTableViewCell.xib in Resources */,
F046DC731FE1786500E3DAF0 /* GroupHomeViewController.xib in Resources */,
F0E5D9141FF6FF3F00560D7F /* GroupRoomTableViewCell.xib in Resources */,
F083BDB71E7009ED00A9B29C /* remove_icon@2x.png in Resources */,
F083BDD31E7009ED00A9B29C /* settings_icon@3x.png in Resources */,
F04AF26B1F83A4C100D20F4D /* Vector.strings in Resources */,
@ -3207,6 +3224,7 @@
F083BD311E7009ED00A9B29C /* bubbles_bg_landscape@2x.png in Resources */,
F0E05A371EA0F9EB004B83FB /* tab_home_selected@2x.png in Resources */,
F0D9F23E1FED1A05001D9A27 /* add_group_participant.png in Resources */,
F0E5D90F1FF6DDCF00560D7F /* GroupRoomsViewController.xib in Resources */,
F083BE651E7009ED00A9B29C /* RoomIncomingTextMsgWithoutSenderNameBubbleCell.xib in Resources */,
F083BD6F1E7009ED00A9B29C /* e2e_blocked@2x.png in Resources */,
);
@ -3272,6 +3290,7 @@
"${PODS_ROOT}/MatrixKit/MatrixKit/Controllers/MXKContactDetailsViewController.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Controllers/MXKContactListViewController.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Controllers/MXKCountryPickerViewController.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Controllers/MXKGroupListViewController.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Controllers/MXKLanguagePickerViewController.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Controllers/MXKRecentListViewController.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Controllers/MXKRoomMemberDetailsViewController.xib",
@ -3285,6 +3304,7 @@
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/Contact/MXKContactTableCell.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/DeviceView/MXKDeviceView.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/Group/MXKGroupTableViewCell.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/MXKCollectionViewCell/MXKMediaCollectionViewCell.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/MXKEventDetailsView.xib",
"${PODS_ROOT}/MatrixKit/MatrixKit/Views/MXKPieChartHUD.xib",
@ -3444,6 +3464,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F0E5D9131FF6FF3F00560D7F /* GroupRoomTableViewCell.m in Sources */,
F083BE221E7009ED00A9B29C /* RoomSettingsViewController.m in Sources */,
F083BE171E7009ED00A9B29C /* MediaPickerViewController.m in Sources */,
F083BE421E7009ED00A9B29C /* RoomIncomingEncryptedTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
@ -3549,6 +3570,7 @@
3233F73F1F331F05006ACA81 /* Widget.m in Sources */,
F083BE191E7009ED00A9B29C /* RecentsViewController.m in Sources */,
F0B4CBA51F418D0B008E99C5 /* WebViewViewController.m in Sources */,
F0E5D90E1FF6DDCF00560D7F /* GroupRoomsViewController.m in Sources */,
F083BE351E7009ED00A9B29C /* MediaAlbumTableCell.m in Sources */,
F083BE4C1E7009ED00A9B29C /* RoomOutgoingEncryptedAttachmentWithoutSenderInfoBubbleCell.m in Sources */,
F075BEDB1EBB26F100A7B68A /* TableViewCellWithCollectionView.m in Sources */,

View file

@ -467,7 +467,6 @@
"group_invitation_format" = "%@ has invited you to join this community";
// Group participants
"group_participants_title" = "Participants";
"group_participants_add_participant" = "Add participant";
"group_participants_leave_prompt_title" = "Leave group";
"group_participants_leave_prompt_msg" = "Are you sure you want to leave the group?";
@ -475,12 +474,15 @@
"group_participants_remove_prompt_msg" = "Are you sure you want to remove %@ from this group?";
"group_participants_invite_prompt_title" = "Confirmation";
"group_participants_invite_prompt_msg" = "Are you sure you want to invite %@ to this group?";
"group_participants_filter_group_members" = "Filter group members";
"group_participants_filter_members" = "Filter community members";
"group_participants_invite_another_user" = "Search / invite by User ID or Name";
"group_participants_invite_malformed_id_title" = "Invite Error";
"group_participants_invite_malformed_id" = "Malformed ID. Should be a Matrix ID like '@localpart:domain'";
"group_participants_invited_section" = "INVITED";
// Group rooms
"group_rooms_filter_rooms" = "Filter community rooms";
// Read Receipts
"read_receipts_list" = "Read Receipts List";
"receipt_status_read" = "Read: ";

View file

@ -379,7 +379,6 @@
"group_home_multi_rooms_format" = "%tu salons";
"group_invitation_format" = "%@ vous a invité à rejoindre cette communauté";
// Group participants
"group_participants_title" = "Membres";
"group_participants_add_participant" = "Ajouter un membre";
"group_participants_leave_prompt_title" = "Quitter le groupe";
"group_participants_leave_prompt_msg" = "Voulez-vous vraiment quitter le groupe?";
@ -387,11 +386,13 @@
"group_participants_remove_prompt_msg" = "Voulez-vous vraiment exclure %@ de ce groupe?";
"group_participants_invite_prompt_title" = "Confirmation";
"group_participants_invite_prompt_msg" = "Voulez-vous vraiment inviter %@ dans ce groupe?";
"group_participants_filter_group_members" = "Filtrer les membres du group";
"group_participants_filter_members" = "Filtrer les membres de la communauté";
"group_participants_invite_another_user" = "Rechercher/inviter par identifiant ou nom";
"group_participants_invite_malformed_id_title" = "Erreur lors de l'invitation";
"group_participants_invite_malformed_id" = "Identifiant au mauvais format. Un identifiant Matrix au format \"@utilisateur:domaine\" est attendu";
"group_participants_invited_section" = "INVITÉS";
// Group rooms
"group_rooms_filter_rooms" = "Filtrer les salons de la communauté";
// Read Receipts
"read_receipts_list" = "Liste des accusés de lecture";
"receipt_status_read" = "Lu : ";

View file

@ -15,8 +15,10 @@
*/
#import "GroupDetailsViewController.h"
#import "GroupHomeViewController.h"
#import "GroupParticipantsViewController.h"
#import "GroupRoomsViewController.h"
#import "AppDelegate.h"
@ -24,6 +26,7 @@
{
GroupHomeViewController *groupHomeViewController;
GroupParticipantsViewController *groupParticipantsViewController;
GroupRoomsViewController *groupRoomsViewController;
/**
mask view while processing a request
@ -98,7 +101,13 @@
[viewControllers addObject:groupParticipantsViewController];
// Rooms tab
//[titles addObject: NSLocalizedStringFromTable(@"group_details_rooms", @"Vector", nil)];
[titles addObject: NSLocalizedStringFromTable(@"group_details_rooms", @"Vector", nil)];
groupRoomsViewController = [GroupRoomsViewController groupRoomsViewController];
if (_group)
{
[groupRoomsViewController setGroup:_group withMatrixSession:_mxSession];
}
[viewControllers addObject:groupRoomsViewController];
self.title = NSLocalizedStringFromTable(@"group_details_title", @"Vector", nil);
[self initWithTitles:titles viewControllers:viewControllers defaultSelected:0];
@ -176,6 +185,10 @@
{
[groupParticipantsViewController setGroup:group withMatrixSession:mxSession];
}
if (groupRoomsViewController)
{
[groupRoomsViewController setGroup:group withMatrixSession:mxSession];
}
}
- (void)withdrawViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion

View file

@ -110,9 +110,7 @@
[NSLayoutConstraint activateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]];
self.navigationItem.title = NSLocalizedStringFromTable(@"group_participants_title", @"Vector", nil);
_searchBarView.placeholder = NSLocalizedStringFromTable(@"group_participants_filter_group_members", @"Vector", nil);
_searchBarView.placeholder = NSLocalizedStringFromTable(@"group_participants_filter_members", @"Vector", nil);
_searchBarView.returnKeyType = UIReturnKeyDone;
_searchBarView.autocapitalizationType = UITextAutocapitalizationTypeNone;
@ -350,8 +348,6 @@
// Refresh the members list.
[self refreshParticipantsList];
[self refreshTableView];
}
- (void)startActivityIndicator
@ -562,17 +558,8 @@
actualParticipants = nil;
invitedParticipants = nil;
}
}
- (void)reloadSearchResult
{
if (currentSearchText.length)
{
NSString *searchText = currentSearchText;
currentSearchText = nil;
[self searchBar:_searchBarView textDidChange:searchText];
}
[self finalizeParticipantsList];
}
- (void)finalizeParticipantsList
@ -601,7 +588,17 @@
[invitedParticipants sortUsingComparator:comparator];
// Reload search result if any
[self reloadSearchResult];
if (currentSearchText.length)
{
NSString *searchText = currentSearchText;
currentSearchText = nil;
[self searchBar:_searchBarView textDidChange:searchText];
}
else
{
[self refreshTableView];
}
}
- (void)addPendingActionMask

View file

@ -0,0 +1,73 @@
/*
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>
/**
'GroupRoomsViewController' instance is used to list the rooms of the group defined by the property 'mxGroup'.
When this property is nil, the view controller is empty.
*/
@interface GroupRoomsViewController : MXKViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate>
{
@protected
/**
The current list of the rooms.
*/
NSArray<MXGroupRoom*> *groupRooms;
}
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UIView *searchBarHeader;
@property (weak, nonatomic) IBOutlet UISearchBar *searchBarView;
@property (weak, nonatomic) IBOutlet UIView *searchBarHeaderBorder;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *searchBarTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewBottomConstraint;
/**
A matrix group (nil by default).
*/
@property (strong, readonly, nonatomic) MXGroup *group;
@property (strong, readonly, nonatomic) MXSession *mxSession;
/**
Returns the `UINib` object initialized for a `GroupRoomsViewController`.
@return The initialized `UINib` object or `nil` if there were errors during initialization
or the nib file could not be located.
*/
+ (UINib *)nib;
/**
Creates and returns a new `GroupRoomsViewController` object.
@discussion This is the designated initializer for programmatic instantiation.
@return An initialized `GroupRoomsViewController` object if successful, `nil` otherwise.
*/
+ (instancetype)groupRoomsViewController;
/**
Set the group for which the rooms are listed.
Provide the related matrix session.
@param group
@param mxSession
*/
- (void)setGroup:(MXGroup*)group withMatrixSession:(MXSession*)mxSession;
@end

View file

@ -0,0 +1,602 @@
/*
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 "GroupRoomsViewController.h"
#import "AppDelegate.h"
#import "GroupRoomTableViewCell.h"
#import "RageShakeManager.h"
@interface GroupRoomsViewController ()
{
// Search result
NSString *currentSearchText;
NSMutableArray<MXGroupRoom*> *filteredGroupRooms;
// Observe kRiotDesignValuesDidChangeThemeNotification to handle user interface theme change.
id kRiotDesignValuesDidChangeThemeNotificationObserver;
}
@end
@implementation GroupRoomsViewController
#pragma mark - Class methods
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass(self.class)
bundle:[NSBundle bundleForClass:self.class]];
}
+ (instancetype)groupRoomsViewController
{
return [[[self class] alloc] initWithNibName:NSStringFromClass(self.class)
bundle:[NSBundle bundleForClass:self.class]];
}
#pragma mark -
- (void)finalizeInit
{
[super finalizeInit];
// Setup `MXKViewControllerHandling` properties
self.enableBarTintColorStatusChange = NO;
self.rageShakeManager = [RageShakeManager sharedManager];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Check whether the view controller has been pushed via storyboard
if (!self.tableView)
{
// Instantiate view controller objects
[[[self class] nib] instantiateWithOwner:self options:nil];
}
// Adjust Top and Bottom constraints to take into account potential navBar and tabBar.
[NSLayoutConstraint deactivateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]];
_searchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.searchBarHeader
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
_tableViewBottomConstraint = [NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.tableView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[_searchBarTopConstraint, _tableViewBottomConstraint]];
_searchBarView.placeholder = NSLocalizedStringFromTable(@"group_rooms_filter_rooms", @"Vector", nil);
_searchBarView.returnKeyType = UIReturnKeyDone;
_searchBarView.autocapitalizationType = UITextAutocapitalizationTypeNone;
// Search bar header is hidden when no group is provided
_searchBarHeader.hidden = (self.group == nil);
// Enable self-sizing cells and section headers.
self.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableView.estimatedRowHeight = 74;
self.tableView.sectionHeaderHeight = 0;
// Hide line separators of empty cells
self.tableView.tableFooterView = [[UIView alloc] init];
[self.tableView registerClass:GroupRoomTableViewCell.class forCellReuseIdentifier:@"RoomTableViewCellId"];
// Observe user interface theme change.
kRiotDesignValuesDidChangeThemeNotificationObserver = [[NSNotificationCenter defaultCenter] addObserverForName:kRiotDesignValuesDidChangeThemeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {
[self userInterfaceThemeDidChange];
}];
[self userInterfaceThemeDidChange];
}
- (void)userInterfaceThemeDidChange
{
self.defaultBarTintColor = kRiotSecondaryBgColor;
self.barTitleColor = kRiotPrimaryTextColor;
self.activityIndicator.backgroundColor = kRiotOverlayColor;
[self refreshSearchBarItemsColor:_searchBarView];
_searchBarHeaderBorder.backgroundColor = kRiotAuxiliaryColor;
// Check the table view style to select its bg color.
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
self.view.backgroundColor = self.tableView.backgroundColor;
if (self.tableView.dataSource)
{
[self.tableView reloadData];
}
}
- (UIStatusBarStyle)preferredStatusBarStyle
{
return kRiotDesignStatusBarStyle;
}
// This method is called when the viewcontroller is added or removed from a container view controller.
- (void)didMoveToParentViewController:(nullable UIViewController *)parent
{
[super didMoveToParentViewController:parent];
}
- (void)destroy
{
if (kRiotDesignValuesDidChangeThemeNotificationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:kRiotDesignValuesDidChangeThemeNotificationObserver];
kRiotDesignValuesDidChangeThemeNotificationObserver = nil;
}
_group = nil;
_mxSession = nil;
filteredGroupRooms = nil;
groupRooms = nil;
[super destroy];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Screen tracking
[[AppDelegate theDelegate] trackScreen:@"GroupDetailsRooms"];
if (_group)
{
// Force refresh
[self didUpdateGroupRooms:nil];
// Trigger a refresh on the group rooms.
[self.mxSession updateGroupRooms:_group success:nil failure:^(NSError *error) {
NSLog(@"[GroupRoomsViewController] viewWillAppear: group rooms update failed %@", _group.groupId);
}];
}
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// cancel any pending search
[self searchBarCancelButtonClicked:_searchBarView];
}
- (void)withdrawViewControllerAnimated:(BOOL)animated completion:(void (^)(void))completion
{
// Check whether the current view controller is displayed inside a segmented view controller in order to withdraw the right item
if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
{
[((SegmentedViewController*)self.parentViewController) withdrawViewControllerAnimated:animated completion:completion];
}
else
{
[super withdrawViewControllerAnimated:animated completion:completion];
}
}
- (void)setGroup:(MXGroup*)group withMatrixSession:(MXSession*)mxSession
{
// Cancel any pending search
[self searchBarCancelButtonClicked:_searchBarView];
_mxSession = mxSession;
[self addMatrixSession:mxSession];
[self refreshDisplayWithGroup:group];
}
#pragma mark -
- (void)registerOnGroupChangeNotifications
{
[self cancelRegistrationOnGroupChangeNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateGroupRooms:) name:kMXSessionDidUpdateGroupRoomsNotification object:self.mxSession];
}
- (void)cancelRegistrationOnGroupChangeNotifications
{
// Remove any pending observers
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)didUpdateGroupRooms:(NSNotification *)notif
{
// Update here the displayed group instance with the one stored in the session (if any).
MXGroup *group = [self.mxSession groupWithGroupId:_group.groupId];
[self refreshDisplayWithGroup:(group ? group : _group)];
}
- (void)refreshDisplayWithGroup:(MXGroup *)group
{
_group = group;
if (_group)
{
_searchBarHeader.hidden = NO;
[self registerOnGroupChangeNotifications];
groupRooms = _group.rooms.chunk;
}
else
{
// Search bar header is hidden when no group is provided
_searchBarHeader.hidden = YES;
[self cancelRegistrationOnGroupChangeNotifications];
groupRooms = nil;
}
// Reload search result if any
if (currentSearchText.length)
{
NSString *searchText = currentSearchText;
currentSearchText = nil;
[self searchBar:_searchBarView textDidChange:searchText];
}
else
{
[self refreshTableView];
}
}
- (void)startActivityIndicator
{
// Check whether the current view controller is displayed inside a segmented view controller in order to run the right activity view
if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
{
[((SegmentedViewController*)self.parentViewController) startActivityIndicator];
// Force stop the activity view of the view controller
[self.activityIndicator stopAnimating];
}
else
{
[super startActivityIndicator];
}
}
- (void)stopActivityIndicator
{
// Check whether the current view controller is displayed inside a segmented view controller in order to stop the right activity view
if (self.parentViewController && [self.parentViewController isKindOfClass:SegmentedViewController.class])
{
[((SegmentedViewController*)self.parentViewController) stopActivityIndicator];
// Force stop the activity view of the view controller
[self.activityIndicator stopAnimating];
}
else
{
[super stopActivityIndicator];
}
}
#pragma mark - Internals
- (void)refreshTableView
{
[self.tableView reloadData];
}
- (void)pushViewController:(UIViewController*)viewController
{
// Check whether the view controller is displayed inside a segmented one.
if (self.parentViewController.navigationController)
{
// Hide back button title
self.parentViewController.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
[self.parentViewController.navigationController pushViewController:viewController animated:YES];
}
else
{
// Hide back button title
self.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
[self.navigationController pushViewController:viewController animated:YES];
}
}
#pragma mark - UITableView data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger count = 0;
if (currentSearchText.length)
{
if (filteredGroupRooms.count)
{
count++;
}
}
else
{
if (groupRooms.count)
{
count++;
}
}
return count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger count = 0;
if (currentSearchText.length)
{
count = filteredGroupRooms.count;
}
else
{
count = groupRooms.count;
}
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GroupRoomTableViewCell* roomCell = [tableView dequeueReusableCellWithIdentifier:@"RoomTableViewCellId" forIndexPath:indexPath];
roomCell.selectionStyle = UITableViewCellSelectionStyleNone;
MXGroupRoom *room;
NSArray *rooms;
if (currentSearchText.length)
{
rooms = filteredGroupRooms;
}
else
{
rooms = groupRooms;
}
if (indexPath.row < rooms.count)
{
room = rooms[indexPath.row];
}
if (room)
{
[roomCell render:room withMatrixSession:self.mxSession];
}
return roomCell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
- (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath
{
// iOS8 requires this method to enable editing (see editActionsForRowAtIndexPath).
}
#pragma mark - UITableView delegate
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return tableView.estimatedRowHeight;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.backgroundColor = kRiotPrimaryBgColor;
// Update the selected background view
if (kRiotSelectedBgColor)
{
cell.selectedBackgroundView = [[UIView alloc] init];
cell.selectedBackgroundView.backgroundColor = kRiotSelectedBgColor;
}
else
{
if (tableView.style == UITableViewStylePlain)
{
cell.selectedBackgroundView = nil;
}
else
{
cell.selectedBackgroundView.backgroundColor = nil;
}
}
// Refresh here the estimated row height
tableView.estimatedRowHeight = cell.frame.size.height;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
//- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
//{
// NSMutableArray* actions;
//
// // @TODO Add the swipe to remove this room from the community if the current user is admin
// actions = [[NSMutableArray alloc] init];
//
// // Patch: Force the width of the button by adding whitespace characters into the title string.
// UITableViewRowAction *leaveAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@" " handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
//
// // @TODO Remove the room
//
// }];
//
// leaveAction.backgroundColor = [MXKTools convertImageToPatternColor:@"remove_icon_blue" backgroundColor:kRiotSecondaryBgColor patternSize:CGSizeMake(74, 74) resourceSize:CGSizeMake(24, 24)];
// [actions insertObject:leaveAction atIndex:0];
//
// return actions;
//}
#pragma mark - UISearchBar delegate
- (void)refreshSearchBarItemsColor:(UISearchBar *)searchBar
{
// bar tint color
searchBar.barTintColor = searchBar.tintColor = kRiotColorBlue;
searchBar.tintColor = kRiotColorBlue;
// FIXME: this all seems incredibly fragile and tied to gutwrenching the current UISearchBar internals.
// text color
UITextField *searchBarTextField = [searchBar valueForKey:@"_searchField"];
searchBarTextField.textColor = kRiotSecondaryTextColor;
// Magnifying glass icon.
UIImageView *leftImageView = (UIImageView *)searchBarTextField.leftView;
leftImageView.image = [leftImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
leftImageView.tintColor = kRiotColorBlue;
// remove the gray background color
UIView *effectBackgroundTop = [searchBarTextField valueForKey:@"_effectBackgroundTop"];
UIView *effectBackgroundBottom = [searchBarTextField valueForKey:@"_effectBackgroundBottom"];
effectBackgroundTop.hidden = YES;
effectBackgroundBottom.hidden = YES;
// place holder
searchBarTextField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:searchBarTextField.placeholder
attributes:@{NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle),
NSUnderlineColorAttributeName: kRiotColorBlue,
NSForegroundColorAttributeName: kRiotColorBlue}];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
// Update search results.
NSUInteger index;
MXGroupRoom *groupRoom;
searchText = [searchText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
if (!currentSearchText.length || [searchText hasPrefix:currentSearchText] == NO)
{
// Copy participants and invited participants
filteredGroupRooms = [NSMutableArray arrayWithArray:groupRooms];
}
currentSearchText = searchText;
// Filter group participants
if (currentSearchText.length)
{
for (index = 0; index < filteredGroupRooms.count;)
{
groupRoom = filteredGroupRooms[index];
NSString *displayName = groupRoom.name;
if (!displayName)
{
displayName = groupRoom.canonicalAlias;
}
if (!displayName)
{
displayName = groupRoom.roomId;
}
if ([displayName rangeOfString:currentSearchText options:NSCaseInsensitiveSearch].location == NSNotFound)
{
[filteredGroupRooms removeObjectAtIndex:index];
}
else
{
index++;
}
}
}
else
{
filteredGroupRooms = nil;
}
// Refresh display
[self refreshTableView];
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
searchBar.showsCancelButton = YES;
return YES;
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar
{
searchBar.showsCancelButton = NO;
return YES;
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
// "Done" key has been pressed.
// Dismiss keyboard
[_searchBarView resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
if (currentSearchText)
{
currentSearchText = nil;
filteredGroupRooms = nil;
[self refreshTableView];
}
searchBar.text = nil;
// Leave search
[searchBar resignFirstResponder];
}
@end

View file

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" 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="13772"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="GroupRoomsViewController">
<connections>
<outlet property="searchBarHeader" destination="Zm7-AB-ZtE" id="6ee-P0-twi"/>
<outlet property="searchBarHeaderBorder" destination="gcy-W7-89G" id="tsy-SP-KaJ"/>
<outlet property="searchBarTopConstraint" destination="sUb-hD-qXJ" id="rzi-JJ-nnP"/>
<outlet property="searchBarView" destination="bsq-3U-VjV" id="x3M-wX-RW8"/>
<outlet property="tableView" destination="kNf-Ll-jvH" id="uzM-uQ-peQ"/>
<outlet property="tableViewBottomConstraint" destination="jLY-ml-Psl" id="Q2b-sC-Yqn"/>
<outlet property="view" destination="iN0-l3-epB" id="csR-cn-S4h"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Zm7-AB-ZtE">
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
<subviews>
<searchBar contentMode="redraw" searchBarStyle="minimal" translatesAutoresizingMaskIntoConstraints="NO" id="bsq-3U-VjV">
<rect key="frame" x="0.0" y="0.0" width="375" height="50"/>
<textInputTraits key="textInputTraits" returnKeyType="done"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="RoomParticipantsVCSearchBarView"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="delegate" destination="-1" id="UYv-bz-JBZ"/>
</connections>
</searchBar>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="gcy-W7-89G">
<rect key="frame" x="0.0" y="49" width="375" height="1"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="Rka-an-qn3"/>
</constraints>
</view>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<accessibility key="accessibilityConfiguration" identifier="RoomParticipantsVCSearchBarHeader"/>
<constraints>
<constraint firstItem="gcy-W7-89G" firstAttribute="leading" secondItem="Zm7-AB-ZtE" secondAttribute="leading" id="4Yn-dN-O2U"/>
<constraint firstItem="bsq-3U-VjV" firstAttribute="leading" secondItem="Zm7-AB-ZtE" secondAttribute="leading" id="6ze-Az-ymf"/>
<constraint firstAttribute="bottom" secondItem="bsq-3U-VjV" secondAttribute="bottom" id="KDW-SI-sG6"/>
<constraint firstAttribute="trailing" secondItem="bsq-3U-VjV" secondAttribute="trailing" id="ZlE-SL-UfQ"/>
<constraint firstAttribute="trailing" secondItem="gcy-W7-89G" secondAttribute="trailing" id="hqD-vA-OM5"/>
<constraint firstAttribute="bottom" secondItem="gcy-W7-89G" secondAttribute="bottom" id="ibU-h7-mHt"/>
<constraint firstAttribute="height" constant="50" id="kSM-fg-IHB"/>
<constraint firstItem="bsq-3U-VjV" firstAttribute="top" secondItem="Zm7-AB-ZtE" secondAttribute="top" id="qpF-Za-XTL"/>
</constraints>
</view>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="onDrag" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="kNf-Ll-jvH">
<rect key="frame" x="0.0" y="50" width="375" height="617"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accessibilityIdentifier" value="RoomParticipantsVCTableView"/>
</userDefinedRuntimeAttributes>
<connections>
<outlet property="dataSource" destination="-1" id="tlI-w1-VJw"/>
<outlet property="delegate" destination="-1" id="xcS-Zy-x2X"/>
</connections>
</tableView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="RoomParticipantsVCView"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Zm7-AB-ZtE" secondAttribute="trailing" id="0W7-Iv-Cs1"/>
<constraint firstAttribute="trailing" secondItem="kNf-Ll-jvH" secondAttribute="trailing" id="1KS-nO-Jys"/>
<constraint firstItem="Zm7-AB-ZtE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="Irh-6y-0cw"/>
<constraint firstItem="kNf-Ll-jvH" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="hfq-4u-4J8"/>
<constraint firstAttribute="bottom" secondItem="kNf-Ll-jvH" secondAttribute="bottom" id="jLY-ml-Psl"/>
<constraint firstItem="Zm7-AB-ZtE" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="sUb-hD-qXJ"/>
<constraint firstItem="kNf-Ll-jvH" firstAttribute="top" secondItem="Zm7-AB-ZtE" secondAttribute="bottom" id="tYv-VV-8dI"/>
</constraints>
</view>
</objects>
</document>

View file

@ -0,0 +1,32 @@
/*
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>
@interface GroupRoomTableViewCell : MXKTableViewCell
@property (weak, nonatomic) IBOutlet UILabel *roomDisplayName;
@property (weak, nonatomic) IBOutlet UILabel *roomTopic;
@property (weak, nonatomic) IBOutlet MXKImageView *roomAvatar;
/**
Configure the cell in order to display a room of a group.
@param groupRoom the room to render.
*/
- (void)render:(MXGroupRoom*)groupRoom withMatrixSession:(MXSession*)mxSession;
@end

View file

@ -0,0 +1,92 @@
/*
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 "GroupRoomTableViewCell.h"
#import "AvatarGenerator.h"
#import "RiotDesignValues.h"
@implementation GroupRoomTableViewCell
- (void)awakeFromNib
{
[super awakeFromNib];
// Round image view
[_roomAvatar.layer setCornerRadius:_roomAvatar.frame.size.width / 2];
_roomAvatar.clipsToBounds = YES;
}
- (void)customizeTableViewCellRendering
{
[super customizeTableViewCellRendering];
self.roomDisplayName.textColor = kRiotPrimaryTextColor;
self.roomTopic.textColor = kRiotSecondaryTextColor;
_roomAvatar.defaultBackgroundColor = [UIColor clearColor];
}
- (void)render:(MXGroupRoom *)groupRoom withMatrixSession:(MXSession*)mxSession
{
// Set room display name
self.roomDisplayName.text = groupRoom.name;
if (!self.roomDisplayName.text)
{
self.roomDisplayName.text = groupRoom.canonicalAlias;
}
if (!self.roomDisplayName.text)
{
self.roomDisplayName.text = groupRoom.roomId;
}
// Check whether this room has topic
if (groupRoom.topic)
{
_roomTopic.hidden = NO;
_roomTopic.text = [MXTools stripNewlineCharacters:groupRoom.topic];
}
else
{
// Hide and fill the label with a fake description to harmonize the height of all the cells.
// This is a drawback of the self-sizing cell.
_roomTopic.hidden = YES;
_roomTopic.text = @"No topic";
}
// Set the avatar
UIImage* avatarImage = [AvatarGenerator generateAvatarForMatrixItem:groupRoom.roomId withDisplayName:self.roomDisplayName.text];
if (groupRoom.avatarUrl)
{
_roomAvatar.enableInMemoryCache = YES;
[_roomAvatar setImageURL:[mxSession.matrixRestClient urlOfContentThumbnail:groupRoom.avatarUrl
toFitViewSize:_roomAvatar.frame.size
withMethod:MXThumbnailingMethodCrop]
withType:nil
andImageOrientation:UIImageOrientationUp previewImage:avatarImage];
}
else
{
_roomAvatar.image = avatarImage;
}
_roomAvatar.contentMode = UIViewContentModeScaleAspectFill;
}
@end

View file

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13771" 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="13772"/>
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
<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 contentMode="scaleToFill" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" id="L2L-l5-wPx" customClass="GroupRoomTableViewCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="74"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="L2L-l5-wPx" id="aXz-IR-jj5">
<rect key="frame" x="0.0" y="0.0" width="600" height="73.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="RX5-eD-c3c" userLabel="Room avatar" customClass="MXKImageView">
<rect key="frame" x="13" y="15" width="42" height="42"/>
<color key="backgroundColor" red="0.89720267057418823" green="0.89720267057418823" blue="0.89720267057418823" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="AvatarImageView"/>
<constraints>
<constraint firstAttribute="width" constant="42" id="7Ys-gS-ja8"/>
<constraint firstAttribute="height" constant="42" id="WPC-tL-hnM"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Lg1-xQ-AGn">
<rect key="frame" x="69" y="14" width="80" height="21"/>
<accessibility key="accessibilityConfiguration" identifier="TitleLabel"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" text="RoomTopic" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontForContentSizeCategory="YES" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dQt-mN-T6b">
<rect key="frame" x="69" y="39" width="75.5" height="20"/>
<accessibility key="accessibilityConfiguration" identifier="DescriptionLabel"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<color key="textColor" red="0.66666666666666663" green="0.66666666666666663" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="Lg1-xQ-AGn" secondAttribute="trailing" constant="8" id="9Xq-sK-5cB"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="leading" secondItem="RX5-eD-c3c" secondAttribute="trailing" constant="14" id="Pgp-JM-oQd"/>
<constraint firstItem="dQt-mN-T6b" firstAttribute="leading" secondItem="RX5-eD-c3c" secondAttribute="trailing" constant="14" id="XFM-LG-4uJ"/>
<constraint firstAttribute="bottom" secondItem="dQt-mN-T6b" secondAttribute="bottom" constant="14" id="Zae-WM-Aqz"/>
<constraint firstItem="dQt-mN-T6b" firstAttribute="top" secondItem="Lg1-xQ-AGn" secondAttribute="bottom" constant="4" id="iaT-57-GOs"/>
<constraint firstItem="RX5-eD-c3c" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="15" id="mga-fG-I0L"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="RX5-eD-c3c" secondAttribute="bottom" constant="15" id="rOh-Sn-aNY"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="dQt-mN-T6b" secondAttribute="trailing" constant="8" id="t2m-pb-5zd"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="14" id="tY3-6V-A3B"/>
<constraint firstItem="RX5-eD-c3c" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" constant="13" id="tgy-cX-Wxm"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<accessibility key="accessibilityConfiguration" identifier="PublicRoomTableViewCell"/>
<connections>
<outlet property="roomAvatar" destination="RX5-eD-c3c" id="XZm-X0-ep1"/>
<outlet property="roomDisplayName" destination="Lg1-xQ-AGn" id="xsu-y3-L5l"/>
<outlet property="roomTopic" destination="dQt-mN-T6b" id="xz7-Kr-2Fu"/>
</connections>
</tableViewCell>
</objects>
</document>