Merge branch 'develop' into gil/SP1_space_creation

This commit is contained in:
Gil Eluard
2022-03-01 10:15:13 +01:00
164 changed files with 3643 additions and 1650 deletions
@@ -107,7 +107,7 @@ NSString *const URLPreviewDidUpdateNotification = @"URLPreviewDidUpdateNotificat
}
else
{
self.tag = RoomBubbleCellDataTagRoomCreateConfiguration;
self.tag = RoomBubbleCellDataTagRoomCreationIntro;
}
// Membership events can be collapsed together
+13 -94
View File
@@ -29,7 +29,7 @@
const CGFloat kTypingCellHeight = 24;
@interface RoomDataSource() <BubbleReactionsViewModelDelegate, URLPreviewViewDelegate, ThreadSummaryViewDelegate>
@interface RoomDataSource() <BubbleReactionsViewModelDelegate, URLPreviewViewDelegate, ThreadSummaryViewDelegate, MXThreadingServiceDelegate>
{
// Observe kThemeServiceDidChangeThemeNotification to handle user interface theme change.
id kThemeServiceDidChangeThemeNotificationObserver;
@@ -92,12 +92,9 @@ const CGFloat kTypingCellHeight = 24;
[self reload];
}];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(newThreadCreated:)
name:MXThreadingService.newThreadCreated
object:nil];
[matrixSession.threadingService addDelegate:self];
[self registerKeyVerificationRequestNotification];
[self registerKeyVerificationTransactionNotification];
[self registerTrustLevelDidChangeNotifications];
@@ -177,6 +174,8 @@ const CGFloat kTypingCellHeight = 24;
{
[[NSNotificationCenter defaultCenter] removeObserver:self.keyVerificationTransactionDidChangeNotificationObserver];
}
[self.mxSession.threadingService removeDelegate:self];
[super destroy];
}
@@ -232,7 +231,6 @@ const CGFloat kTypingCellHeight = 24;
}
[self fetchEncryptionTrustedLevel];
[self enableRoomCreationIntroCellDisplayIfNeeded];
}
- (void)fetchEncryptionTrustedLevel
@@ -241,11 +239,6 @@ const CGFloat kTypingCellHeight = 24;
[self.roomDataSourceDelegate roomDataSourceDidUpdateEncryptionTrustLevel:self];
}
- (void)roomDidSet
{
[self enableRoomCreationIntroCellDisplayIfNeeded];
}
- (BOOL)shouldQueueEventForProcessing:(MXEvent *)event roomState:(MXRoomState *)roomState direction:(MXTimelineDirection)direction
{
if (self.threadId)
@@ -303,8 +296,6 @@ const CGFloat kTypingCellHeight = 24;
// Enable the containsLastMessage flag for the cell data which contains the last message.
@synchronized(bubbles)
{
[self insertRoomCreationIntroCellDataIfNeeded];
// Reset first all cell data
for (RoomBubbleCellData *cellData in bubbles)
{
@@ -973,15 +964,20 @@ const CGFloat kTypingCellHeight = 24;
cell.attachmentView.accessibilityLabel = nil;
}
#pragma mark - Threads
#pragma mark - MXThreadingServiceDelegate
- (void)newThreadCreated:(NSNotification *)notification
- (void)threadingService:(MXThreadingService *)service didCreateNewThread:(MXThread *)thread direction:(MXTimelineDirection)direction
{
if (self.threadId)
{
// no need to reload the thread screen
return;
}
if (direction == MXTimelineDirectionBackwards)
{
// no need to reload when paginating back
return;
}
NSUInteger count = 0;
@synchronized (bubbles)
{
@@ -1091,83 +1087,6 @@ const CGFloat kTypingCellHeight = 24;
}
}
#pragma mark - Room creation intro cell
- (BOOL)canShowRoomCreationIntroCell
{
NSString* userId = self.mxSession.myUser.userId;
if (!userId || !self.isLive || self.isPeeking)
{
return NO;
}
// Room creation cell is only shown for the creator
return [self.room.summary.creatorUserId isEqualToString:userId];
}
- (void)enableRoomCreationIntroCellDisplayIfNeeded
{
self.showRoomCreationCell = [self canShowRoomCreationIntroCell];
}
// Insert the room creation intro cell at the begining
- (void)insertRoomCreationIntroCellDataIfNeeded
{
@synchronized(bubbles)
{
NSUInteger existingRoomCreationCellDataIndex = [self roomBubbleDataIndexWithTag:RoomBubbleCellDataTagRoomCreationIntro];
if (existingRoomCreationCellDataIndex != NSNotFound)
{
[bubbles removeObjectAtIndex:existingRoomCreationCellDataIndex];
}
if (self.showRoomCreationCell)
{
NSUInteger roomCreationConfigCellDataIndex = [self roomBubbleDataIndexWithTag:RoomBubbleCellDataTagRoomCreateConfiguration];
// Only add room creation intro cell if `bubbles` array contains the room creation event
if (roomCreationConfigCellDataIndex != NSNotFound)
{
if (!self.roomCreationCellData)
{
MXEvent *event = [MXEvent new];
MXRoomState *roomState = [MXRoomState new];
RoomBubbleCellData *roomBubbleCellData = [[RoomBubbleCellData alloc] initWithEvent:event andRoomState:roomState andRoomDataSource:self];
roomBubbleCellData.tag = RoomBubbleCellDataTagRoomCreationIntro;
self.roomCreationCellData = roomBubbleCellData;
}
[bubbles insertObject:self.roomCreationCellData atIndex:0];
}
}
else
{
self.roomCreationCellData = nil;
}
}
}
- (NSUInteger)roomBubbleDataIndexWithTag:(RoomBubbleCellDataTag)tag
{
@synchronized(bubbles)
{
return [bubbles indexOfObjectPassingTest:^BOOL(id<MXKRoomBubbleCellDataStoring> _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:RoomBubbleCellData.class])
{
RoomBubbleCellData *roomBubbleCellData = (RoomBubbleCellData*)obj;
if (roomBubbleCellData.tag == tag)
{
return YES;
}
}
return NO;
}];
}
}
#pragma mark - URLPreviewViewDelegate
- (void)didOpenURLFromPreviewView:(URLPreviewView *)previewView for:(NSString *)eventID in:(NSString *)roomID
@@ -102,6 +102,11 @@ typedef NS_ENUM(NSUInteger, MXKRoomViewControllerJoinRoomResult) {
*/
@property (nonatomic, readonly) MXKRoomDataSource *roomDataSource;
/**
The data source associated to live timeline, in the case the view controller show timeline not live.
*/
@property (nonatomic) MXKRoomDataSource *roomDataSourceLive;
/**
Flag indicating if this instance has the memory ownership of its `roomDataSource`.
If YES, it will release it on [self destroy] call;
+10 -4
View File
@@ -680,9 +680,9 @@
if (dataSource)
{
if (!dataSource.isLive || dataSource.isPeeking)
if (dataSource.isPeeking)
{
// Remove the input toolbar if the displayed timeline is not a live one or in case of peeking.
// Remove the input toolbar in case of peeking.
// We do not let the user type message in this case.
[self setRoomInputToolbarViewClass:nil];
}
@@ -1085,9 +1085,9 @@
inputToolbarView = nil;
}
if (roomDataSource && (!roomDataSource.isLive || roomDataSource.isPeeking))
if (roomDataSource && roomDataSource.isPeeking)
{
// Do not show the input toolbar if the displayed timeline is not a live one, or in case of peeking.
// Do not show the input toolbar if the displayed timeline in case of peeking.
// We do not let the user type message in this case.
roomInputToolbarViewClass = nil;
}
@@ -2348,6 +2348,12 @@
{
// Do a full reload
[_bubblesTableView reloadData];
if (shouldScrollToBottom) {
// If we need to scroll to the bottom after the reload, layout refresh needs to be triggered,
// otherwise contentSize of the table view will not be up-to-date
// e.g. https://stackoverflow.com/a/31324129
[_bubblesTableView layoutIfNeeded];
}
}
if (shouldScrollToBottom)
@@ -17,6 +17,8 @@
*/
import UIKit
import CommonKit
import MatrixSDK
final class RoomInfoListViewController: UIViewController {
@@ -38,7 +40,7 @@ final class RoomInfoListViewController: UIViewController {
private var viewModel: RoomInfoListViewModelType!
private var theme: Theme!
private var errorPresenter: MXKErrorPresentation!
private var activityPresenter: ActivityIndicatorPresenter!
private var activityPresenter: ActivityIndicatorPresenterType!
private var isRoomDirect: Bool = false
private var screenTimer = AnalyticsScreenTimer(screen: .roomDetails)
@@ -114,7 +116,14 @@ final class RoomInfoListViewController: UIViewController {
// Do any additional setup after loading the view.
self.setupViews()
self.activityPresenter = ActivityIndicatorPresenter()
if BuildSettings.useAppUserIndicators {
self.activityPresenter = FullscreenActivityIndicatorPresenter(
label: VectorL10n.roomParticipantsLeaveProcessing,
viewController: self
)
} else {
self.activityPresenter = ActivityIndicatorPresenter()
}
self.errorPresenter = MXKErrorAlertPresentation()
self.registerThemeServiceDidChangeThemeNotification()
@@ -143,6 +152,7 @@ final class RoomInfoListViewController: UIViewController {
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
screenTimer.stop()
activityPresenter.removeCurrentActivityIndicator(animated: animated)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
+78 -50
View File
@@ -1073,15 +1073,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
self.jumpToLastUnreadBannerContainer.hidden = YES;
[super leaveRoomOnEvent:event];
if (self.delegate)
{
[self.delegate roomViewControllerDidLeaveRoom:self];
}
else
{
[[AppDelegate theDelegate] restoreInitialDisplay:nil];
}
[self notifyDelegateOnLeaveRoomIfNecessary];
}
// Set the input toolbar according to the current display
@@ -1261,33 +1253,69 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (void)sendTextMessage:(NSString*)msgTxt
{
if (self.inputToolBarSendMode == RoomInputToolbarViewSendModeReply && customizedRoomDataSource.selectedEventId)
// The event modified is always fetch from the actual data source
MXEvent *eventModified = [self.roomDataSource eventWithEventId:customizedRoomDataSource.selectedEventId];
// In the case the event is a reply or and edit, and it's done on a non-live timeline
// we have to fetch live timeline in order to display the event properly
[self setupRoomDataSourceToResolveEvent:^(MXKRoomDataSource *roomDataSource) {
if (self.inputToolBarSendMode == RoomInputToolbarViewSendModeReply && eventModified)
{
[roomDataSource sendReplyToEvent:eventModified withTextMessage:msgTxt success:nil failure:^(NSError *error) {
// Just log the error. The message will be displayed in red in the room history
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
}];
}
else if (self.inputToolBarSendMode == RoomInputToolbarViewSendModeEdit && eventModified)
{
[roomDataSource replaceTextMessageForEvent:eventModified withTextMessage:msgTxt success:nil failure:^(NSError *error) {
// Just log the error. The message will be displayed in red
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
}];
}
else
{
// Let the datasource send it and manage the local echo
[roomDataSource sendTextMessage:msgTxt success:nil failure:^(NSError *error)
{
// Just log the error. The message will be displayed in red in the room history
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
}];
}
if (self->customizedRoomDataSource.selectedEventId)
{
[self cancelEventSelection];
}
}];
}
- (void)setupRoomDataSourceToResolveEvent: (void (^)(MXKRoomDataSource *roomDataSource))onComplete
{
// If the event occur on timeline not live, use the live data source to resolve event
BOOL isLive = self.roomDataSource.isLive;
if (!isLive)
{
[self.roomDataSource sendReplyToEventWithId:customizedRoomDataSource.selectedEventId withTextMessage:msgTxt success:nil failure:^(NSError *error) {
// Just log the error. The message will be displayed in red in the room history
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
}];
}
else if (self.inputToolBarSendMode == RoomInputToolbarViewSendModeEdit && customizedRoomDataSource.selectedEventId)
{
[self.roomDataSource replaceTextMessageForEventWithId:customizedRoomDataSource.selectedEventId withTextMessage:msgTxt success:nil failure:^(NSError *error) {
// Just log the error. The message will be displayed in red
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
}];
if (self.roomDataSourceLive == nil)
{
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mainSession];
[roomDataSourceManager roomDataSourceForRoom:self.roomDataSource.roomId
create:YES
onComplete:^(MXKRoomDataSource *roomDataSource) {
self.roomDataSourceLive = roomDataSource;
[self.roomDataSourceLive finalizeInitialization];
onComplete(self.roomDataSourceLive);
}];
}
else
{
onComplete(self.roomDataSourceLive);
}
}
else
{
// Let the datasource send it and manage the local echo
[self.roomDataSource sendTextMessage:msgTxt success:nil failure:^(NSError *error)
{
// Just log the error. The message will be displayed in red in the room history
MXLogDebug(@"[MXKRoomViewController] sendTextMessage failed.");
}];
}
if (customizedRoomDataSource.selectedEventId)
{
[self cancelEventSelection];
onComplete(self.roomDataSource);
}
}
@@ -2201,16 +2229,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[self.roomDataSource.room leave:^{
[self stopActivityIndicator];
// We remove the current view controller.
if (self.delegate)
{
[self.delegate roomViewControllerDidLeaveRoom:self];
}
else
{
[[AppDelegate theDelegate] restoreInitialDisplay:^{}];
}
[self notifyDelegateOnLeaveRoomIfNecessary];
} failure:^(NSError *error) {
@@ -2220,6 +2239,22 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
}];
}
- (void)notifyDelegateOnLeaveRoomIfNecessary {
if (self.delegate)
{
// Leaving room often triggers multiple events, incl local delegate callbacks as well as global notifications,
// which may lead to multiple identical UI changes (navigating to home, displaying notification etc).
// To avoid this, as soon as we notify the delegate the first time, we nilify it, preventing future messages
// from being passed along, assuming that after leaving a room there is nothing else to communicate to the delegate.
[self.delegate roomViewControllerDidLeaveRoom:self];
self.delegate = nil;
}
else
{
[[AppDelegate theDelegate] restoreInitialDisplay:^{}];
}
}
- (void)roomPreviewDidTapCancelAction
{
// Decline this invitation = leave this page
@@ -7040,14 +7075,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (void)roomInfoCoordinatorBridgePresenterDelegateDidLeaveRoom:(RoomInfoCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
if (self.delegate)
{
[self.delegate roomViewControllerDidLeaveRoom:self];
}
else
{
[[AppDelegate theDelegate] restoreInitialDisplay:nil];
}
[self notifyDelegateOnLeaveRoomIfNecessary];
}
- (void)roomInfoCoordinatorBridgePresenter:(RoomInfoCoordinatorBridgePresenter *)coordinatorBridgePresenter didReplaceRoomWithReplacementId:(NSString *)roomId
+3 -3
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@@ -189,7 +189,7 @@
<constraint firstAttribute="bottom" secondItem="BGD-sd-SQR" secondAttribute="bottom" constant="41" id="1SD-y2-oTg"/>
<constraint firstItem="Xt7-83-dQh" firstAttribute="leading" secondItem="QpJ-1u-4ii" secondAttribute="leading" id="6lr-Tx-pEb"/>
<constraint firstItem="QpJ-1u-4ii" firstAttribute="trailing" secondItem="Ih9-EU-BOU" secondAttribute="trailing" constant="16" id="6rq-lR-0sB"/>
<constraint firstItem="54r-18-K1g" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="7Ft-EV-Br0"/>
<constraint firstItem="54r-18-K1g" firstAttribute="top" secondItem="QpJ-1u-4ii" secondAttribute="top" id="7Ft-EV-Br0"/>
<constraint firstItem="gt1-EO-UVY" firstAttribute="leading" secondItem="QpJ-1u-4ii" secondAttribute="leading" id="8Ff-Ot-h3F"/>
<constraint firstItem="Xt7-83-dQh" firstAttribute="bottom" secondItem="iN0-l3-epB" secondAttribute="bottom" id="9g2-wm-4M9"/>
<constraint firstItem="fmF-ad-erE" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="DtG-PR-F24"/>
@@ -124,7 +124,7 @@ class BaseRoomCell: MXKRoomBubbleTableViewCell, BaseRoomCellProtocol {
}
}
override var readMarkerViewLeadingConstraint: NSLayoutConstraint! {
override var readMarkerViewLeadingConstraint: NSLayoutConstraint? {
get {
if self is RoomCellReadMarkerDisplayable {
return self.roomCellContentView?.readMarkerViewLeadingConstraint
@@ -141,7 +141,7 @@ class BaseRoomCell: MXKRoomBubbleTableViewCell, BaseRoomCellProtocol {
}
}
override var readMarkerViewTrailingConstraint: NSLayoutConstraint! {
override var readMarkerViewTrailingConstraint: NSLayoutConstraint? {
get {
if self is RoomCellReadMarkerDisplayable {
return self.roomCellContentView?.readMarkerViewTrailingConstraint
@@ -228,11 +228,11 @@ extern NSString *const kMXKRoomBubbleCellUrlItemInteraction;
/**
The read marker view and its layout constraints (nil by default).
*/
@property (nonatomic) UIView *readMarkerView;
@property (nonatomic) NSLayoutConstraint *readMarkerViewTopConstraint;
@property (nonatomic) NSLayoutConstraint *readMarkerViewLeadingConstraint;
@property (nonatomic) NSLayoutConstraint *readMarkerViewTrailingConstraint;
@property (nonatomic) NSLayoutConstraint *readMarkerViewHeightConstraint;
@property (nonatomic, nullable) UIView *readMarkerView;
@property (nonatomic, nullable) NSLayoutConstraint *readMarkerViewTopConstraint;
@property (nonatomic, nullable) NSLayoutConstraint *readMarkerViewLeadingConstraint;
@property (nonatomic, nullable) NSLayoutConstraint *readMarkerViewTrailingConstraint;
@property (nonatomic, nullable) NSLayoutConstraint *readMarkerViewHeightConstraint;
/**
The potential webview used to render an attachment (for example an animated gif).
@@ -273,8 +273,8 @@ class PlainRoomTimelineCellDecorator: RoomTimelineCellDecorator {
let readMarkerContainerViewHalfWidth = readMarkerContainerView.frame.size.width/2
cell.readMarkerViewLeadingConstraint.constant = readMarkerContainerViewHalfWidth
cell.readMarkerViewTrailingConstraint.constant = -readMarkerContainerViewHalfWidth
cell.readMarkerViewLeadingConstraint?.constant = readMarkerContainerViewHalfWidth
cell.readMarkerViewTrailingConstraint?.constant = -readMarkerContainerViewHalfWidth
UIView.animate(withDuration: 1.5,
delay: 0.3,