Remove all types related to Groups

This commit is contained in:
Doug
2022-08-05 12:26:48 +01:00
committed by Doug
parent 061211bbfc
commit 3e9e946506
44 changed files with 0 additions and 7563 deletions
@@ -1,118 +0,0 @@
/*
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 <UIKit/UIKit.h>
#import "MXKViewController.h"
#import "MXKSessionGroupsDataSource.h"
@class MXKGroupListViewController;
/**
`MXKGroupListViewController` delegate.
*/
@protocol MXKGroupListViewControllerDelegate <NSObject>
/**
Tells the delegate that the user selected a group.
@param groupListViewController the `MXKGroupListViewController` instance.
@param group the selected group.
@param mxSession the matrix session in which the group is defined.
*/
- (void)groupListViewController:(MXKGroupListViewController *)groupListViewController didSelectGroup:(MXGroup*)group inMatrixSession:(MXSession*)mxSession;
@end
/**
This view controller displays a group list.
*/
@interface MXKGroupListViewController : MXKViewController <MXKDataSourceDelegate, UITableViewDelegate, UISearchBarDelegate>
{
@protected
/**
The fake top view displayed in case of vertical bounce.
*/
__weak UIView *topview;
}
@property (weak, nonatomic) IBOutlet UISearchBar *groupsSearchBar;
@property (weak, nonatomic) IBOutlet UITableView *groupsTableView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *groupsSearchBarTopConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *groupsSearchBarHeightConstraint;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *groupsTableViewBottomConstraint;
/**
The current data source associated to the view controller.
*/
@property (nonatomic, readonly) MXKSessionGroupsDataSource *dataSource;
/**
The delegate for the view controller.
*/
@property (nonatomic, weak) id<MXKGroupListViewControllerDelegate> delegate;
/**
Enable the search option by adding a navigation item in the navigation bar (YES by default).
Set NO this property to disable this option and hide the related bar button.
*/
@property (nonatomic) BOOL enableBarButtonSearch;
#pragma mark - Class methods
/**
Returns the `UINib` object initialized for a `MXKGroupListViewController`.
@return The initialized `UINib` object or `nil` if there were errors during initialization
or the nib file could not be located.
@discussion You may override this method to provide a customized nib. If you do,
you should also override `groupListViewController` to return your
view controller loaded from your custom nib.
*/
+ (UINib *)nib;
/**
Creates and returns a new `MXKGroupListViewController` object.
@discussion This is the designated initializer for programmatic instantiation.
@return An initialized `MXKGroupListViewController` object if successful, `nil` otherwise.
*/
+ (instancetype)groupListViewController;
/**
Display the groups described in the provided data source.
Note: The provided data source will replace the current data source if any. The caller
should dispose properly this data source if it is not used anymore.
@param listDataSource the data source providing the groups list.
*/
- (void)displayList:(MXKSessionGroupsDataSource*)listDataSource;
/**
Refresh the groups table display.
*/
- (void)refreshGroupsTable;
/**
Hide/show the search bar at the top of the groups table view.
*/
- (void)hideSearchBar:(BOOL)hidden;
@end
@@ -1,614 +0,0 @@
/*
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 "MXKGroupListViewController.h"
#import "MXKGroupTableViewCell.h"
#import "MXKTableViewHeaderFooterWithLabel.h"
@interface MXKGroupListViewController ()
{
/**
The data source providing UITableViewCells
*/
MXKSessionGroupsDataSource *dataSource;
/**
Search handling
*/
UIBarButtonItem *searchButton;
BOOL ignoreSearchRequest;
/**
The reconnection animated view.
*/
UIView* reconnectingView;
/**
The current table view header if any.
*/
UIView* tableViewHeaderView;
/**
The latest server sync date
*/
NSDate* latestServerSync;
/**
The restart the event connnection
*/
BOOL restartConnection;
}
@end
@implementation MXKGroupListViewController
@synthesize dataSource;
#pragma mark - Class methods
+ (UINib *)nib
{
return [UINib nibWithNibName:NSStringFromClass([MXKGroupListViewController class])
bundle:[NSBundle bundleForClass:[MXKGroupListViewController class]]];
}
+ (instancetype)groupListViewController
{
return [[[self class] alloc] initWithNibName:NSStringFromClass([MXKGroupListViewController class])
bundle:[NSBundle bundleForClass:[MXKGroupListViewController class]]];
}
#pragma mark -
- (void)finalizeInit
{
[super finalizeInit];
_enableBarButtonSearch = YES;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Check whether the view controller has been pushed via storyboard
if (!_groupsTableView)
{
// Instantiate view controller objects
[[[self class] nib] instantiateWithOwner:self options:nil];
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
// Adjust search bar Top constraint to take into account potential navBar.
if (_groupsSearchBarTopConstraint)
{
[NSLayoutConstraint deactivateConstraints:@[_groupsSearchBarTopConstraint]];
_groupsSearchBarTopConstraint = [NSLayoutConstraint constraintWithItem:self.topLayoutGuide
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.groupsSearchBar
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[_groupsSearchBarTopConstraint]];
}
// Adjust table view Bottom constraint to take into account tabBar.
if (_groupsTableViewBottomConstraint)
{
[NSLayoutConstraint deactivateConstraints:@[_groupsTableViewBottomConstraint]];
_groupsTableViewBottomConstraint = [NSLayoutConstraint constraintWithItem:self.bottomLayoutGuide
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.groupsTableView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.0f];
[NSLayoutConstraint activateConstraints:@[_groupsTableViewBottomConstraint]];
}
#pragma clang diagnostic pop
// Hide search bar by default
[self hideSearchBar:YES];
// Apply search option in navigation bar
self.enableBarButtonSearch = _enableBarButtonSearch;
// Add an accessory view to the search bar in order to retrieve keyboard view.
self.groupsSearchBar.inputAccessoryView = [[UIView alloc] initWithFrame:CGRectZero];
// Finalize table view configuration
// Note: self-sizing cells and self-sizing section headers are enabled from the nib file.
self.groupsTableView.delegate = self;
self.groupsTableView.dataSource = dataSource; // Note: dataSource may be nil here
self.groupsTableView.estimatedSectionHeaderHeight = 30; // The value set in the nib seems not available for iOS version < 10.
// Set up classes to use for the cells and the section headers.
[self.groupsTableView registerNib:MXKGroupTableViewCell.nib forCellReuseIdentifier:MXKGroupTableViewCell.defaultReuseIdentifier];
[self.groupsTableView registerNib:MXKTableViewHeaderFooterWithLabel.nib forHeaderFooterViewReuseIdentifier:MXKTableViewHeaderFooterWithLabel.defaultReuseIdentifier];
// Add a top view which will be displayed in case of vertical bounce.
CGFloat height = self.groupsTableView.frame.size.height;
UIView *topview = [[UIView alloc] initWithFrame:CGRectMake(0,-height,self.groupsTableView.frame.size.width,height)];
topview.autoresizingMask = UIViewAutoresizingFlexibleWidth;
topview.backgroundColor = [UIColor groupTableViewBackgroundColor];
[self.groupsTableView addSubview:topview];
self->topview = topview;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Restore search mechanism (if enabled)
ignoreSearchRequest = NO;
// Observe the server sync
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onSyncNotification) name:kMXSessionDidSyncNotification object:nil];
// Do a full reload
[self refreshGroupsTable];
// Refresh all groups summary
[self.dataSource refreshGroupsSummary:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// The user may still press search button whereas the view disappears
ignoreSearchRequest = YES;
// Leave potential search session
if (!self.groupsSearchBar.isHidden)
{
[self searchBarCancelButtonClicked:self.groupsSearchBar];
}
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidSyncNotification object:nil];
[self removeReconnectingView];
}
- (void)dealloc
{
self.groupsSearchBar.inputAccessoryView = nil;
searchButton = nil;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Override MXKViewController
- (void)onKeyboardShowAnimationComplete
{
// Report the keyboard view in order to track keyboard frame changes
self.keyboardView = _groupsSearchBar.inputAccessoryView.superview;
}
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated"
- (void)setKeyboardHeight:(CGFloat)keyboardHeight
{
// Deduce the bottom constraint for the table view (Don't forget the potential tabBar)
CGFloat tableViewBottomConst = keyboardHeight - self.bottomLayoutGuide.length;
// Check whether the keyboard is over the tabBar
if (tableViewBottomConst < 0)
{
tableViewBottomConst = 0;
}
// Update constraints
_groupsTableViewBottomConstraint.constant = tableViewBottomConst;
// Force layout immediately to take into account new constraint
[self.view layoutIfNeeded];
}
#pragma clang diagnostic pop
- (void)destroy
{
self.groupsTableView.dataSource = nil;
self.groupsTableView.delegate = nil;
self.groupsTableView = nil;
dataSource.delegate = nil;
dataSource = nil;
_delegate = nil;
[topview removeFromSuperview];
topview = nil;
[super destroy];
}
#pragma mark -
- (void)setEnableBarButtonSearch:(BOOL)enableBarButtonSearch
{
_enableBarButtonSearch = enableBarButtonSearch;
if (enableBarButtonSearch)
{
if (!searchButton)
{
searchButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:@selector(search:)];
}
// Add it in right bar items
NSArray *rightBarButtonItems = self.navigationItem.rightBarButtonItems;
self.navigationItem.rightBarButtonItems = rightBarButtonItems ? [rightBarButtonItems arrayByAddingObject:searchButton] : @[searchButton];
}
else
{
NSMutableArray *rightBarButtonItems = [NSMutableArray arrayWithArray: self.navigationItem.rightBarButtonItems];
[rightBarButtonItems removeObject:searchButton];
self.navigationItem.rightBarButtonItems = rightBarButtonItems;
}
}
- (void)displayList:(MXKSessionGroupsDataSource *)listDataSource
{
// Cancel registration on existing dataSource if any
if (dataSource)
{
dataSource.delegate = nil;
// Remove associated matrix sessions
NSArray *mxSessions = self.mxSessions;
for (MXSession *mxSession in mxSessions)
{
[self removeMatrixSession:mxSession];
}
}
dataSource = listDataSource;
dataSource.delegate = self;
// Report the matrix session at view controller level to update UI according to session state
[self addMatrixSession:listDataSource.mxSession];
if (self.groupsTableView)
{
// Set up table data source
self.groupsTableView.dataSource = dataSource;
}
}
- (void)refreshGroupsTable
{
// For now, do a simple full reload
[self.groupsTableView reloadData];
}
- (void)hideSearchBar:(BOOL)hidden
{
self.groupsSearchBar.hidden = hidden;
self.groupsSearchBarHeightConstraint.constant = hidden ? 0 : 44;
[self.view setNeedsUpdateConstraints];
}
#pragma mark - Action
- (IBAction)search:(id)sender
{
// The user may have pressed search button whereas the view controller was disappearing
if (ignoreSearchRequest)
{
return;
}
if (self.groupsSearchBar.isHidden)
{
// Check whether there are data in which search
if ([self.dataSource numberOfSectionsInTableView:self.groupsTableView])
{
[self hideSearchBar:NO];
// Create search bar
[self.groupsSearchBar becomeFirstResponder];
}
}
else
{
[self searchBarCancelButtonClicked: self.groupsSearchBar];
}
}
#pragma mark - MXKDataSourceDelegate
- (Class<MXKCellRendering>)cellViewClassForCellData:(MXKCellData*)cellData
{
// Return the default group table view cell
return MXKGroupTableViewCell.class;
}
- (NSString *)cellReuseIdentifierForCellData:(MXKCellData*)cellData
{
// Return the default group table view cell
return MXKGroupTableViewCell.defaultReuseIdentifier;
}
- (void)dataSource:(MXKDataSource *)dataSource didCellChange:(id)changes
{
// For now, do a simple full reload
[self refreshGroupsTable];
}
- (void)dataSource:(MXKDataSource *)dataSource didAddMatrixSession:(MXSession *)mxSession
{
[self addMatrixSession:mxSession];
}
- (void)dataSource:(MXKDataSource *)dataSource didRemoveMatrixSession:(MXSession *)mxSession
{
[self removeMatrixSession:mxSession];
}
#pragma mark - UITableView delegate
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return tableView.estimatedRowHeight;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section
{
if (tableView.numberOfSections > 1)
{
return tableView.estimatedSectionHeaderHeight;
}
return 0;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
// Refresh here the estimated row height
tableView.estimatedRowHeight = cell.frame.size.height;
}
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(nonnull UIView *)view forSection:(NSInteger)section
{
// Refresh here the estimated header height
tableView.estimatedSectionHeaderHeight = view.frame.size.height;
}
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
MXKTableViewHeaderFooterWithLabel *sectionHeader;
if (tableView.numberOfSections > 1)
{
sectionHeader = [tableView dequeueReusableHeaderFooterViewWithIdentifier:MXKTableViewHeaderFooterWithLabel.defaultReuseIdentifier];
sectionHeader.mxkLabel.text = [self.dataSource tableView:tableView titleForHeaderInSection:section];
}
return sectionHeader;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_delegate)
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell conformsToProtocol:@protocol(MXKCellRendering)])
{
id<MXKCellRendering> cell = (id<MXKCellRendering>)selectedCell;
if ([cell respondsToSelector:@selector(renderedCellData)])
{
MXKCellData *cellData = cell.renderedCellData;
if ([cellData conformsToProtocol:@protocol(MXKGroupCellDataStoring)])
{
id<MXKGroupCellDataStoring> groupCellData = (id<MXKGroupCellDataStoring>)cellData;
[_delegate groupListViewController:self didSelectGroup:groupCellData.group inMatrixSession:self.mainSession];
}
}
}
}
// Hide the keyboard when user select a room
// do not hide the searchBar until the view controller disappear
// on tablets / iphone 6+, the user could expect to search again while looking at a room
[self.groupsSearchBar resignFirstResponder];
}
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
{
// Release here resources, and restore reusable cells
if ([cell respondsToSelector:@selector(didEndDisplay)])
{
[(id<MXKCellRendering>)cell didEndDisplay];
}
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
// Detect vertical bounce at the top of the tableview to trigger reconnection.
if (scrollView == _groupsTableView)
{
[self detectPullToKick:scrollView];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
if (scrollView == _groupsTableView)
{
[self managePullToKick:scrollView];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == _groupsTableView)
{
if (scrollView.contentOffset.y + scrollView.adjustedContentInset.top == 0)
{
[self managePullToKick:scrollView];
}
}
}
#pragma mark - UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
// Apply filter
if (searchText.length)
{
[self.dataSource searchWithPatterns:@[searchText]];
}
else
{
[self.dataSource searchWithPatterns:nil];
}
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
// "Done" key has been pressed
[searchBar resignFirstResponder];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
// Leave search
[searchBar resignFirstResponder];
[self hideSearchBar:YES];
self.groupsSearchBar.text = nil;
// Refresh display
[self.dataSource searchWithPatterns:nil];
}
#pragma mark - resync management
- (void)onSyncNotification
{
latestServerSync = [NSDate date];
MXWeakify(self);
// Refresh all groups summary
[self.dataSource refreshGroupsSummary:^{
MXStrongifyAndReturnIfNil(self);
[self removeReconnectingView];
}];
}
- (BOOL)canReconnect
{
// avoid restarting connection if some data has been received within 1 second (1000 : latestServerSync is null)
NSTimeInterval interval = latestServerSync ? [[NSDate date] timeIntervalSinceDate:latestServerSync] : 1000;
return (interval > 1) && [self.mainSession reconnect];
}
- (void)addReconnectingView
{
if (!reconnectingView)
{
UIActivityIndicatorView* spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
spinner.transform = CGAffineTransformMakeScale(0.75f, 0.75f);
CGRect frame = spinner.frame;
frame.size.height = 80; // 80 * 0.75 = 60
spinner.bounds = frame;
spinner.color = [UIColor darkGrayColor];
spinner.hidesWhenStopped = NO;
spinner.backgroundColor = _groupsTableView.backgroundColor;
[spinner startAnimating];
// no need to manage constraints here, IOS defines them.
tableViewHeaderView = _groupsTableView.tableHeaderView;
_groupsTableView.tableHeaderView = reconnectingView = spinner;
}
}
- (void)removeReconnectingView
{
if (reconnectingView && !restartConnection)
{
_groupsTableView.tableHeaderView = tableViewHeaderView;
reconnectingView = nil;
}
}
/**
Detect if the current connection must be restarted.
The spinner is displayed until the overscroll ends (and scrollViewDidEndDecelerating is called).
*/
- (void)detectPullToKick:(UIScrollView *)scrollView
{
if (!reconnectingView)
{
// detect if the user scrolls over the tableview top
restartConnection = (scrollView.contentOffset.y + scrollView.adjustedContentInset.top < -128);
if (restartConnection)
{
// wait that list decelerate to display / hide it
[self addReconnectingView];
}
}
}
/**
Restarts the current connection if it is required.
The 0.3s delay is added to avoid flickering if the connection does not require to be restarted.
*/
- (void)managePullToKick:(UIScrollView *)scrollView
{
// the current connection must be restarted
if (restartConnection)
{
// display at least 0.3s the spinner to show to the user that something is pending
// else the UI is flickering
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
self->restartConnection = NO;
if (![self canReconnect])
{
// if the event stream has not been restarted
// hide the spinner
[self removeReconnectingView];
}
// else wait that onSyncNotification is called.
});
}
}
@end
@@ -1,53 +0,0 @@
<?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>
<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="MXKGroupListViewController">
<connections>
<outlet property="groupsSearchBar" destination="Zbr-9e-VZh" id="lBZ-hu-yJo"/>
<outlet property="groupsSearchBarHeightConstraint" destination="jCU-cq-2OA" id="Nl4-Wn-L98"/>
<outlet property="groupsSearchBarTopConstraint" destination="aRg-Nz-enq" id="mDZ-YB-gRX"/>
<outlet property="groupsTableView" destination="orV-HH-88x" id="pZt-dT-XPy"/>
<outlet property="groupsTableViewBottomConstraint" destination="m4x-32-odR" id="4hx-dQ-8aj"/>
<outlet property="view" destination="iN0-l3-epB" id="NUQ-LI-M61"/>
</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>
<searchBar contentMode="redraw" showsCancelButton="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Zbr-9e-VZh">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<constraints>
<constraint firstAttribute="height" constant="44" id="jCU-cq-2OA"/>
</constraints>
<textInputTraits key="textInputTraits" returnKeyType="done"/>
<connections>
<outlet property="delegate" destination="-1" id="ejZ-kN-jKv"/>
</connections>
</searchBar>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="interactive" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="70" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="30" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="orV-HH-88x">
<rect key="frame" x="0.0" y="44" width="375" height="623"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</tableView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="orV-HH-88x" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="NaR-eJ-WMj"/>
<constraint firstItem="Zbr-9e-VZh" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="aRg-Nz-enq"/>
<constraint firstItem="Zbr-9e-VZh" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="fty-XB-tTr"/>
<constraint firstItem="orV-HH-88x" firstAttribute="top" secondItem="Zbr-9e-VZh" secondAttribute="bottom" id="lBa-P2-Vnx"/>
<constraint firstAttribute="bottom" secondItem="orV-HH-88x" secondAttribute="bottom" id="m4x-32-odR"/>
<constraint firstAttribute="trailing" secondItem="Zbr-9e-VZh" secondAttribute="trailing" id="rKb-TZ-sap"/>
<constraint firstAttribute="trailing" secondItem="orV-HH-88x" secondAttribute="trailing" id="yBp-63-kZi"/>
</constraints>
</view>
</objects>
</document>
@@ -1,24 +0,0 @@
/*
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 "MXKGroupCellDataStoring.h"
/**
`MXKGroupCellData` modelised the data for a `MXKGroupTableViewCell` cell.
*/
@interface MXKGroupCellData : MXKCellData <MXKGroupCellDataStoring>
@end
@@ -1,49 +0,0 @@
/*
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 "MXKGroupCellData.h"
#import "MXKSessionGroupsDataSource.h"
@implementation MXKGroupCellData
@synthesize group, groupsDataSource, groupDisplayname, sortingDisplayname;
- (instancetype)initWithGroup:(MXGroup*)theGroup andGroupsDataSource:(MXKSessionGroupsDataSource*)theGroupsDataSource
{
self = [self init];
if (self)
{
groupsDataSource = theGroupsDataSource;
[self updateWithGroup:theGroup];
}
return self;
}
- (void)updateWithGroup:(MXGroup*)theGroup
{
group = theGroup;
groupDisplayname = sortingDisplayname = group.profile.name;
if (!groupDisplayname.length)
{
groupDisplayname = group.groupId;
// Ignore the prefix '+' of the group id during sorting.
sortingDisplayname = [groupDisplayname substringFromIndex:1];
}
}
@end
@@ -1,53 +0,0 @@
/*
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 <MatrixSDK/MatrixSDK.h>
#import "MXKCellData.h"
@class MXKSessionGroupsDataSource;
/**
`MXKGroupCellDataStoring` defines a protocol a class must conform in order to store group cell data
managed by `MXKSessionGroupsDataSource`.
*/
@protocol MXKGroupCellDataStoring <NSObject>
@property (nonatomic, weak, readonly) MXKSessionGroupsDataSource *groupsDataSource;
@property (nonatomic, readonly) MXGroup *group;
@property (nonatomic, readonly) NSString *groupDisplayname;
@property (nonatomic, readonly) NSString *sortingDisplayname;
#pragma mark - Public methods
/**
Create a new `MXKCellData` object for a new group cell.
@param group the `MXGroup` object that has data about the group.
@param groupsDataSource the `MXKSessionGroupsDataSource` object that will use this instance.
@return the newly created instance.
*/
- (instancetype)initWithGroup:(MXGroup*)group andGroupsDataSource:(MXKSessionGroupsDataSource*)groupsDataSource;
/**
The `MXKSessionGroupsDataSource` object calls this method when the group data has been updated.
@param group the updated group.
*/
- (void)updateWithGroup:(MXGroup*)group;
@end
@@ -1,94 +0,0 @@
/*
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 "MXKDataSource.h"
#import "MXKGroupCellData.h"
/**
Identifier to use for cells that display a group.
*/
extern NSString *const kMXKGroupCellIdentifier;
/**
'MXKSessionGroupsDataSource' is a base class to handle the groups of a matrix session.
A 'MXKSessionGroupsDataSource' instance provides the data source for `MXKGroupListViewController`.
A section is created to handle the invitations to a group, the first one if any.
*/
@interface MXKSessionGroupsDataSource : MXKDataSource <UITableViewDataSource>
{
@protected
/**
The current list of the group invitations (sorted in the alphabetic order).
This list takes into account potential filter defined by`patternsList`.
*/
NSMutableArray<MXKGroupCellData*> *groupsInviteCellDataArray;
/**
The current displayed list of the joined groups (sorted in the alphabetic order).
This list takes into account potential filter defined by`patternsList`.
*/
NSMutableArray<MXKGroupCellData*> *groupsCellDataArray;
}
@property (nonatomic) NSInteger groupInvitesSection;
@property (nonatomic) NSInteger joinedGroupsSection;
#pragma mark - Life cycle
/**
Refresh all the groups summary.
The group data are not synced with the server, use this method to refresh them according to your needs.
@param completion the block to execute when a request has been done for each group (whatever the result of the requests).
You may specify nil for this parameter.
*/
- (void)refreshGroupsSummary:(void (^)(void))completion;
/**
Filter the current groups list according to the provided patterns.
When patterns are not empty, the search result is stored in `filteredGroupsCellDataArray`,
this array provides then data for the cells served by `MXKSessionGroupsDataSource`.
@param patternsList the list of patterns (`NSString` instances) to match with. Set nil to cancel search.
*/
- (void)searchWithPatterns:(NSArray*)patternsList;
/**
Get the data for the cell at the given index path.
@param indexPath the index of the cell in the table
@return the cell data
*/
- (id<MXKGroupCellDataStoring>)cellDataAtIndex:(NSIndexPath*)indexPath;
/**
Get the index path of the cell related to the provided groupId.
@param groupId the group identifier.
@return indexPath the index of the cell (nil if not found).
*/
- (NSIndexPath*)cellIndexPathWithGroupId:(NSString*)groupId;
/**
Leave the group displayed at the provided path.
@param indexPath the index of the group cell in the table
*/
- (void)leaveGroupAtIndexPath:(NSIndexPath *)indexPath;
@end
@@ -1,611 +0,0 @@
/*
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C
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 "MXKSessionGroupsDataSource.h"
#import "NSBundle+MatrixKit.h"
#import "MXKConstants.h"
#import "MXKSwiftHeader.h"
#pragma mark - Constant definitions
NSString *const kMXKGroupCellIdentifier = @"kMXKGroupCellIdentifier";
@interface MXKSessionGroupsDataSource ()
{
/**
Internal array used to regulate change notifications.
Cell data changes are stored instantly in this array.
We wait at least for 500 ms between two notifications of the delegate.
*/
NSMutableArray *internalCellDataArray;
/*
Timer to not notify the delegate on every changes.
*/
NSTimer *timer;
/*
Tells whether some changes must be notified.
*/
BOOL isDataChangePending;
/**
Store the current search patterns list.
*/
NSArray* searchPatternsList;
}
@end
@implementation MXKSessionGroupsDataSource
- (instancetype)initWithMatrixSession:(MXSession *)matrixSession
{
self = [super initWithMatrixSession:matrixSession];
if (self)
{
internalCellDataArray = [NSMutableArray array];
groupsCellDataArray = [NSMutableArray array];
groupsInviteCellDataArray = [NSMutableArray array];
isDataChangePending = NO;
// Set default data and view classes
[self registerCellDataClass:MXKGroupCellData.class forCellIdentifier:kMXKGroupCellIdentifier];
}
return self;
}
- (void)destroy
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
groupsCellDataArray = nil;
groupsInviteCellDataArray = nil;
internalCellDataArray = nil;
searchPatternsList = nil;
[timer invalidate];
timer = nil;
[super destroy];
}
- (void)didMXSessionStateChange
{
if (MXSessionStateRunning <= self.mxSession.state)
{
// Check whether some data have been already load
if (0 == internalCellDataArray.count)
{
[self loadData];
}
else if (self.mxSession.state == MXSessionStateRunning)
{
// Refresh the group data
[self refreshGroupsSummary:nil];
}
}
}
#pragma mark -
- (void)refreshGroupsSummary:(void (^)(void))completion
{
MXLogDebug(@"[MXKSessionGroupsDataSource] refreshGroupsSummary");
__block NSUInteger count = internalCellDataArray.count;
if (count)
{
for (id<MXKGroupCellDataStoring> groupData in internalCellDataArray)
{
// Force the matrix session to refresh the group summary.
[self.mxSession updateGroupSummary:groupData.group success:^{
if (completion && !(--count))
{
// All the requests have been done.
completion ();
}
} failure:^(NSError *error) {
MXLogDebug(@"[MXKSessionGroupsDataSource] refreshGroupsSummary: group summary update failed %@", groupData.group.groupId);
if (completion && !(--count))
{
// All the requests have been done.
completion ();
}
}];
}
}
else if (completion)
{
completion();
}
}
- (void)searchWithPatterns:(NSArray*)patternsList
{
if (patternsList.count)
{
searchPatternsList = patternsList;
}
else
{
searchPatternsList = nil;
}
[self onCellDataChange];
}
- (id<MXKGroupCellDataStoring>)cellDataAtIndex:(NSIndexPath*)indexPath
{
id<MXKGroupCellDataStoring> groupData;
if (indexPath.section == _groupInvitesSection)
{
if (indexPath.row < groupsInviteCellDataArray.count)
{
groupData = groupsInviteCellDataArray[indexPath.row];
}
}
else if (indexPath.section == _joinedGroupsSection)
{
if (indexPath.row < groupsCellDataArray.count)
{
groupData = groupsCellDataArray[indexPath.row];
}
}
return groupData;
}
- (NSIndexPath*)cellIndexPathWithGroupId:(NSString*)groupId
{
// Look for the cell
if (_groupInvitesSection != -1)
{
for (NSInteger index = 0; index < groupsInviteCellDataArray.count; index ++)
{
id<MXKGroupCellDataStoring> groupData = groupsInviteCellDataArray[index];
if ([groupId isEqualToString:groupData.group.groupId])
{
// Got it
return [NSIndexPath indexPathForRow:index inSection:_groupInvitesSection];
}
}
}
if (_joinedGroupsSection != -1)
{
for (NSInteger index = 0; index < groupsCellDataArray.count; index ++)
{
id<MXKGroupCellDataStoring> groupData = groupsCellDataArray[index];
if ([groupId isEqualToString:groupData.group.groupId])
{
// Got it
return [NSIndexPath indexPathForRow:index inSection:_joinedGroupsSection];
}
}
}
return nil;
}
#pragma mark - Groups processing
- (void)loadData
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionNewGroupInviteNotification object:self.mxSession];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidJoinGroupNotification object:self.mxSession];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidLeaveGroupNotification object:self.mxSession];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kMXSessionDidUpdateGroupSummaryNotification object:self.mxSession];
// Reset the table
[internalCellDataArray removeAllObjects];
// Retrieve the MXKCellData class to manage the data
Class class = [self cellDataClassForCellIdentifier:kMXKGroupCellIdentifier];
NSAssert([class conformsToProtocol:@protocol(MXKGroupCellDataStoring)], @"MXKSessionGroupsDataSource only manages MXKCellData that conforms to MXKGroupCellDataStoring protocol");
// Listen to MXSession groups changes
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onNewGroupInvite:) name:kMXSessionNewGroupInviteNotification object:self.mxSession];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didJoinGroup:) name:kMXSessionDidJoinGroupNotification object:self.mxSession];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didLeaveGroup:) name:kMXSessionDidLeaveGroupNotification object:self.mxSession];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didUpdateGroup:) name:kMXSessionDidUpdateGroupSummaryNotification object:self.mxSession];
NSDate *startDate = [NSDate date];
NSArray *groups = self.mxSession.groups;
for (MXGroup *group in groups)
{
id<MXKGroupCellDataStoring> cellData = [[class alloc] initWithGroup:group andGroupsDataSource:self];
if (cellData)
{
[internalCellDataArray addObject:cellData];
// Force the matrix session to refresh the group summary.
[self.mxSession updateGroupSummary:group success:nil failure:^(NSError *error) {
MXLogDebug(@"[MXKSessionGroupsDataSource] loadData: group summary update failed %@", group.groupId);
}];
}
}
MXLogDebug(@"[MXKSessionGroupsDataSource] Loaded %tu groups in %.3fms", groups.count, [[NSDate date] timeIntervalSinceDate:startDate] * 1000);
[self sortCellData];
[self onCellDataChange];
}
- (void)didUpdateGroup:(NSNotification *)notif
{
MXGroup *group = notif.userInfo[kMXSessionNotificationGroupKey];
if (group)
{
id<MXKGroupCellDataStoring> groupData = [self cellDataWithGroupId:group.groupId];
if (groupData)
{
[groupData updateWithGroup:group];
}
else
{
MXLogDebug(@"[MXKSessionGroupsDataSource] didUpdateGroup: Cannot find the changed group for %@ (%@). It is probably not managed by this group data source", group.groupId, group);
return;
}
}
[self sortCellData];
[self onCellDataChange];
}
- (void)onNewGroupInvite:(NSNotification *)notif
{
MXGroup *group = notif.userInfo[kMXSessionNotificationGroupKey];
if (group)
{
// Add the group if there is not yet a cell for it
id<MXKGroupCellDataStoring> groupData = [self cellDataWithGroupId:group.groupId];
if (nil == groupData)
{
MXLogDebug(@"MXKSessionGroupsDataSource] Add new group invite: %@", group.groupId);
// Retrieve the MXKCellData class to manage the data
Class class = [self cellDataClassForCellIdentifier:kMXKGroupCellIdentifier];
id<MXKGroupCellDataStoring> cellData = [[class alloc] initWithGroup:group andGroupsDataSource:self];
if (cellData)
{
[internalCellDataArray addObject:cellData];
[self sortCellData];
[self onCellDataChange];
}
}
}
}
- (void)didJoinGroup:(NSNotification *)notif
{
MXGroup *group = notif.userInfo[kMXSessionNotificationGroupKey];
if (group)
{
id<MXKGroupCellDataStoring> groupData = [self cellDataWithGroupId:group.groupId];
if (groupData)
{
MXLogDebug(@"MXKSessionGroupsDataSource] Update joined room: %@", group.groupId);
[groupData updateWithGroup:group];
}
else
{
MXLogDebug(@"MXKSessionGroupsDataSource] Add new joined invite: %@", group.groupId);
// Retrieve the MXKCellData class to manage the data
Class class = [self cellDataClassForCellIdentifier:kMXKGroupCellIdentifier];
id<MXKGroupCellDataStoring> cellData = [[class alloc] initWithGroup:group andGroupsDataSource:self];
if (cellData)
{
[internalCellDataArray addObject:cellData];
}
}
[self sortCellData];
[self onCellDataChange];
}
}
- (void)didLeaveGroup:(NSNotification *)notif
{
NSString *groupId = notif.userInfo[kMXSessionNotificationGroupIdKey];
if (groupId)
{
[self removeGroup:groupId];
}
}
- (void)removeGroup:(NSString*)groupId
{
id<MXKGroupCellDataStoring> groupData = [self cellDataWithGroupId:groupId];
if (groupData)
{
MXLogDebug(@"MXKSessionGroupsDataSource] Remove left group: %@", groupId);
[internalCellDataArray removeObject:groupData];
[self sortCellData];
[self onCellDataChange];
}
}
- (void)onCellDataChange
{
isDataChangePending = NO;
// Check no notification was done recently.
// Note: do not wait in case of search
if (timer == nil || searchPatternsList)
{
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(checkPendingUpdate:) userInfo:nil repeats:NO];
// Prepare cell data array, and notify the delegate.
[self prepareCellDataAndNotifyChanges];
}
else
{
isDataChangePending = YES;
}
}
- (IBAction)checkPendingUpdate:(id)sender
{
[timer invalidate];
timer = nil;
if (isDataChangePending)
{
[self onCellDataChange];
}
}
- (void)sortCellData
{
// Order alphabetically the groups
[internalCellDataArray sortUsingComparator:^NSComparisonResult(id<MXKGroupCellDataStoring> cellData1, id<MXKGroupCellDataStoring> cellData2)
{
if (cellData1.sortingDisplayname.length && cellData2.sortingDisplayname.length)
{
return [cellData1.sortingDisplayname compare:cellData2.sortingDisplayname options:NSCaseInsensitiveSearch];
}
else if (cellData1.sortingDisplayname.length)
{
return NSOrderedAscending;
}
else if (cellData2.sortingDisplayname.length)
{
return NSOrderedDescending;
}
return NSOrderedSame;
}];
}
- (void)prepareCellDataAndNotifyChanges
{
// Prepare the cell data arrays by considering the potential filter.
[groupsInviteCellDataArray removeAllObjects];
[groupsCellDataArray removeAllObjects];
for (id<MXKGroupCellDataStoring> groupData in internalCellDataArray)
{
BOOL isKept = !searchPatternsList;
for (NSString* pattern in searchPatternsList)
{
if (groupData.groupDisplayname && [groupData.groupDisplayname rangeOfString:pattern options:NSCaseInsensitiveSearch].location != NSNotFound)
{
isKept = YES;
break;
}
}
if (isKept)
{
if (groupData.group.membership == MXMembershipInvite)
{
[groupsInviteCellDataArray addObject:groupData];
}
else
{
[groupsCellDataArray addObject:groupData];
}
}
}
// Update here data source state
if (state != MXKDataSourceStateReady)
{
state = MXKDataSourceStateReady;
if (self.delegate && [self.delegate respondsToSelector:@selector(dataSource:didStateChange:)])
{
[self.delegate dataSource:self didStateChange:state];
}
}
// And inform the delegate about the update
[self.delegate dataSource:self didCellChange:nil];
}
// Find the cell data that stores information about the given group id
- (id<MXKGroupCellDataStoring>)cellDataWithGroupId:(NSString*)groupId
{
id<MXKGroupCellDataStoring> theGroupData;
for (id<MXKGroupCellDataStoring> groupData in internalCellDataArray)
{
if ([groupData.group.groupId isEqualToString:groupId])
{
theGroupData = groupData;
break;
}
}
return theGroupData;
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger count = 0;
_groupInvitesSection = _joinedGroupsSection = -1;
// Check whether all data sources are ready before rendering groups.
if (self.state == MXKDataSourceStateReady)
{
if (groupsInviteCellDataArray.count)
{
_groupInvitesSection = count++;
}
if (groupsCellDataArray.count)
{
_joinedGroupsSection = count++;
}
}
return count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == _groupInvitesSection)
{
return groupsInviteCellDataArray.count;
}
else if (section == _joinedGroupsSection)
{
return groupsCellDataArray.count;
}
return 0;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
NSString* sectionTitle = nil;
if (section == _groupInvitesSection)
{
sectionTitle = [VectorL10n groupInviteSection];
}
else if (section == _joinedGroupsSection)
{
sectionTitle = [VectorL10n groupSection];
}
return sectionTitle;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
id<MXKGroupCellDataStoring> groupData;
if (indexPath.section == _groupInvitesSection)
{
if (indexPath.row < groupsInviteCellDataArray.count)
{
groupData = groupsInviteCellDataArray[indexPath.row];
}
}
else if (indexPath.section == _joinedGroupsSection)
{
if (indexPath.row < groupsCellDataArray.count)
{
groupData = groupsCellDataArray[indexPath.row];
}
}
if (groupData)
{
NSString *cellIdentifier = [self.delegate cellReuseIdentifierForCellData:groupData];
if (cellIdentifier)
{
UITableViewCell<MXKCellRendering> *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
// Make sure we listen to user actions on the cell
cell.delegate = self;
// Make the bubble display the data
[cell render:groupData];
return cell;
}
}
// Return a fake cell to prevent app from crashing.
return [[UITableViewCell alloc] init];
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self leaveGroupAtIndexPath:indexPath];
}
}
- (void)leaveGroupAtIndexPath:(NSIndexPath *)indexPath
{
id<MXKGroupCellDataStoring> cellData = [self cellDataAtIndex:indexPath];
if (cellData.group)
{
__weak typeof(self) weakSelf = self;
[self.mxSession leaveGroup:cellData.group.groupId success:^{
if (weakSelf)
{
// Refresh the table content
typeof(self) self = weakSelf;
[self removeGroup:cellData.group.groupId];
}
} failure:^(NSError *error) {
MXLogDebug(@"[MXKSessionGroupsDataSource] Failed to leave group (%@)", cellData.group.groupId);
// Notify MatrixKit user
NSString *myUserId = self.mxSession.myUser.userId;
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
}];
}
}
@end
@@ -1,39 +0,0 @@
/*
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 "MXKTableViewCell.h"
#import "MXKCellRendering.h"
#import "MXKGroupCellDataStoring.h"
/**
`MXKGroupTableViewCell` instances display a group.
*/
@interface MXKGroupTableViewCell : MXKTableViewCell <MXKCellRendering>
{
@protected
/**
The current cell data displayed by the table view cell
*/
id<MXKGroupCellDataStoring> groupCellData;
}
@property (weak, nonatomic) IBOutlet UILabel *groupName;
@property (weak, nonatomic) IBOutlet UILabel *groupDescription;
@property (weak, nonatomic) IBOutlet UILabel *memberCount;
@end
@@ -1,92 +0,0 @@
/*
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 "MXKGroupTableViewCell.h"
#import "NSBundle+MatrixKit.h"
#import "MXKSwiftHeader.h"
@implementation MXKGroupTableViewCell
@synthesize delegate;
#pragma mark - Class methods
- (void)render:(MXKCellData *)cellData
{
groupCellData = (id<MXKGroupCellDataStoring>)cellData;
if (groupCellData)
{
// Render the current group values.
_groupName.text = groupCellData.groupDisplayname;
_groupDescription.text = groupCellData.group.profile.shortDescription;
if (_groupDescription.text.length)
{
_groupDescription.hidden = NO;
}
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.
_groupDescription.hidden = YES;
_groupDescription.text = @"No description";
}
if (_memberCount)
{
if (groupCellData.group.summary.usersSection.totalUserCountEstimate > 1)
{
_memberCount.text = [VectorL10n numMembersOther:@(groupCellData.group.summary.usersSection.totalUserCountEstimate).stringValue];
}
else if (groupCellData.group.summary.usersSection.totalUserCountEstimate == 1)
{
_memberCount.text = [VectorL10n numMembersOne:@(1).stringValue];
}
else
{
_memberCount.text = nil;
}
}
}
else
{
_groupName.text = nil;
_groupDescription.text = nil;
_memberCount.text = nil;
}
}
- (MXKCellData*)renderedCellData
{
return groupCellData;
}
+ (CGFloat)heightForCellData:(MXKCellData *)cellData withMaximumWidth:(CGFloat)maxWidth
{
// The height is fixed
//@TODO: change this to handle dynamic font
return 70;
}
- (void)prepareForReuse
{
[super prepareForReuse];
groupCellData = nil;
}
@end
@@ -1,62 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13529" 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="13527"/>
<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="MXKGroupTableViewCell">
<rect key="frame" x="0.0" y="0.0" width="600" height="70"/>
<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="69.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" text="RoomTitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="Lg1-xQ-AGn">
<rect key="frame" x="8" y="8" width="506" height="23"/>
<fontDescription key="fontDescription" type="system" pointSize="19"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="LastEventDescription" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dQt-mN-T6b">
<rect key="frame" x="8" y="42" width="584" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="xx users" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="360-Go-RcG">
<rect key="frame" x="520" y="8" width="72" height="18"/>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="72" id="uOj-6w-G8q"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" constant="8" id="3qc-BC-FYt"/>
<constraint firstItem="360-Go-RcG" firstAttribute="leading" secondItem="Lg1-xQ-AGn" secondAttribute="trailing" constant="6" id="8ff-tS-Ulq"/>
<constraint firstItem="dQt-mN-T6b" firstAttribute="leading" secondItem="aXz-IR-jj5" secondAttribute="leading" constant="8" id="UYQ-HG-YP1"/>
<constraint firstItem="360-Go-RcG" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="8" id="XyO-tl-6SX"/>
<constraint firstAttribute="trailing" secondItem="360-Go-RcG" secondAttribute="trailing" constant="8" id="YqC-WC-Wqe"/>
<constraint firstAttribute="bottom" secondItem="dQt-mN-T6b" secondAttribute="bottom" constant="9" id="sLb-Q4-AFW"/>
<constraint firstItem="Lg1-xQ-AGn" firstAttribute="top" secondItem="aXz-IR-jj5" secondAttribute="top" constant="8" id="uCT-KE-X09"/>
<constraint firstAttribute="trailing" secondItem="dQt-mN-T6b" secondAttribute="trailing" constant="8" id="ygG-1B-fu3"/>
</constraints>
</tableViewCellContentView>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<connections>
<outlet property="groupDescription" destination="dQt-mN-T6b" id="meF-te-1lf"/>
<outlet property="groupName" destination="Lg1-xQ-AGn" id="ABQ-44-bUs"/>
<outlet property="memberCount" destination="360-Go-RcG" id="oYv-dg-CoR"/>
</connections>
</tableViewCell>
</objects>
</document>