mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-27 19:56:57 +02:00
Merge branch 'develop' into steve/5210_bubble_polls
This commit is contained in:
@@ -45,6 +45,11 @@
|
||||
*/
|
||||
@property(nonatomic) BOOL showBubbleDateTimeOnSelection;
|
||||
|
||||
/**
|
||||
Flag to decide displaying typing row in the data source. Default is YES.
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL showTypingRow;
|
||||
|
||||
/**
|
||||
Current room members trust level for an encrypted room.
|
||||
*/
|
||||
|
||||
@@ -132,6 +132,8 @@ const CGFloat kTypingCellHeight = 24;
|
||||
[self.room.summary enableTrustTracking:YES];
|
||||
[self fetchEncryptionTrustedLevel];
|
||||
}
|
||||
|
||||
self.showTypingRow = YES;
|
||||
}
|
||||
|
||||
- (id<RoomDataSourceDelegate>)roomDataSourceDelegate
|
||||
@@ -269,7 +271,7 @@ const CGFloat kTypingCellHeight = 24;
|
||||
else if (RiotSettings.shared.enableThreads)
|
||||
{
|
||||
// if not in a thread, ignore all threaded events
|
||||
if (event.threadId)
|
||||
if (event.isInThread)
|
||||
{
|
||||
// ignore the event
|
||||
return NO;
|
||||
@@ -279,7 +281,7 @@ const CGFloat kTypingCellHeight = 24;
|
||||
{
|
||||
MXEvent *relatedEvent = [self.mxSession.store eventWithEventId:event.relatesTo.eventId
|
||||
inRoom:event.roomId];
|
||||
if (relatedEvent.threadId)
|
||||
if (relatedEvent.isInThread)
|
||||
{
|
||||
// ignore the event
|
||||
return NO;
|
||||
@@ -325,28 +327,30 @@ const CGFloat kTypingCellHeight = 24;
|
||||
[self updateStatusInfo];
|
||||
}
|
||||
|
||||
if (!self.currentTypingUsers)
|
||||
if (self.showTypingRow && self.currentTypingUsers)
|
||||
{
|
||||
self.typingCellIndex = bubbles.count;
|
||||
return bubbles.count + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.typingCellIndex = -1;
|
||||
|
||||
// we may have changed the number of bubbles in this block, consider that change
|
||||
return bubbles.count;
|
||||
}
|
||||
|
||||
self.typingCellIndex = bubbles.count;
|
||||
return bubbles.count + 1;
|
||||
}
|
||||
|
||||
if (!self.currentTypingUsers)
|
||||
if (self.showTypingRow && self.currentTypingUsers)
|
||||
{
|
||||
self.typingCellIndex = count;
|
||||
return count + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.typingCellIndex = -1;
|
||||
|
||||
|
||||
// leave it as is, if coming as 0 from super
|
||||
return count;
|
||||
}
|
||||
|
||||
self.typingCellIndex = count;
|
||||
return count + 1;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
||||
@@ -19,6 +19,27 @@ import Foundation
|
||||
@objcMembers
|
||||
public class ThreadDataSource: RoomDataSource {
|
||||
|
||||
public override func finalizeInitialization() {
|
||||
super.finalizeInitialization()
|
||||
showReadMarker = false
|
||||
showBubbleReceipts = false
|
||||
showTypingRow = false
|
||||
}
|
||||
|
||||
public override var showReadMarker: Bool {
|
||||
get {
|
||||
return false
|
||||
} set {
|
||||
_ = newValue
|
||||
}
|
||||
}
|
||||
|
||||
public override var showBubbleReceipts: Bool {
|
||||
get {
|
||||
return false
|
||||
} set {
|
||||
_ = newValue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
|
||||
override func awakeFromNib() {
|
||||
super.awakeFromNib()
|
||||
|
||||
mapView = MGLMapView(frame: .zero, styleURL: BuildSettings.tileServerMapURL)
|
||||
mapView = MGLMapView(frame: .zero)
|
||||
mapView.delegate = self
|
||||
mapView.logoView.isHidden = true
|
||||
mapView.attributionButton.isHidden = true
|
||||
@@ -72,7 +72,11 @@ class RoomTimelineLocationView: UIView, NibLoadable, Themable, MGLMapViewDelegat
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
public func displayLocation(_ location: CLLocationCoordinate2D, userAvatarData: AvatarViewData? = nil) {
|
||||
public func displayLocation(_ location: CLLocationCoordinate2D,
|
||||
userAvatarData: AvatarViewData? = nil,
|
||||
mapStyleURL: URL) {
|
||||
|
||||
mapView.styleURL = mapStyleURL
|
||||
|
||||
annotationView = LocationMarkerView.loadFromNib()
|
||||
|
||||
|
||||
@@ -214,7 +214,7 @@
|
||||
if (membersListener)
|
||||
{
|
||||
MXWeakify(self);
|
||||
[self.mxRoom liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
[self.mxRoom liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[liveTimeline removeListener:self->membersListener];
|
||||
@@ -333,7 +333,7 @@
|
||||
if (self->membersListener)
|
||||
{
|
||||
MXWeakify(self);
|
||||
[self.mxRoom liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
[self.mxRoom liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[liveTimeline removeListener:self->membersListener];
|
||||
@@ -399,7 +399,7 @@
|
||||
NSArray *mxMembersEvents = @[kMXEventTypeStringRoomMember, kMXEventTypeStringRoomThirdPartyInvite, kMXEventTypeStringRoomPowerLevels];
|
||||
|
||||
MXWeakify(self);
|
||||
[self.mxRoom liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
[self.mxRoom liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
self->membersListener = [liveTimeline listenToEventsOfTypes:mxMembersEvents onEvent:^(MXEvent *event, MXTimelineDirection direction, id customObject) {
|
||||
|
||||
@@ -206,9 +206,9 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
|
||||
// Present activity indicator when retrieving roomDataSource for given room ID
|
||||
self.activityIndicatorPresenter.presentActivityIndicator(on: roomViewController.view, animated: false)
|
||||
|
||||
// Open the room on the requested event
|
||||
// Open the thread on the requested event
|
||||
ThreadDataSource.load(withRoomId: roomId,
|
||||
initialEventId: nil,
|
||||
initialEventId: eventId,
|
||||
threadId: threadId,
|
||||
andMatrixSession: self.parameters.session) { [weak self] (dataSource) in
|
||||
|
||||
@@ -386,6 +386,14 @@ extension RoomCoordinator: RoomViewControllerDelegate {
|
||||
startLocationCoordinatorWithEvent(event, bubbleData: bubbleData)
|
||||
}
|
||||
|
||||
func roomViewController(_ roomViewController: RoomViewController, locationShareActivityViewControllerFor event: MXEvent) -> UIActivityViewController? {
|
||||
guard let location = event.location else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return LocationSharingCoordinator.shareLocationActivityController(CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude))
|
||||
}
|
||||
|
||||
func roomViewController(_ roomViewController: RoomViewController, canEndPollWithEventIdentifier eventIdentifier: String) -> Bool {
|
||||
guard #available(iOS 14.0, *) else {
|
||||
return false
|
||||
|
||||
@@ -219,6 +219,9 @@ handleUniversalLinkWithParameters:(UniversalLinkParameters*)parameters;
|
||||
didRequestLocationPresentationForEvent:(MXEvent *)event
|
||||
bubbleData:(id<MXKRoomBubbleCellDataStoring>)bubbleData;
|
||||
|
||||
- (nullable UIActivityViewController *)roomViewController:(RoomViewController *)roomViewController
|
||||
locationShareActivityViewControllerForEvent:(MXEvent *)event;
|
||||
|
||||
- (BOOL)roomViewController:(RoomViewController *)roomViewController
|
||||
canEndPollWithEventIdentifier:(NSString *)eventIdentifier;
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
@interface RoomViewController () <UISearchBarDelegate, UIGestureRecognizerDelegate, UIScrollViewAccessibilityDelegate, RoomTitleViewTapGestureDelegate, RoomParticipantsViewControllerDelegate, MXKRoomMemberDetailsViewControllerDelegate, ContactsTableViewControllerDelegate, MXServerNoticesDelegate, RoomContextualMenuViewControllerDelegate,
|
||||
ReactionsMenuViewModelCoordinatorDelegate, EditHistoryCoordinatorBridgePresenterDelegate, MXKDocumentPickerPresenterDelegate, EmojiPickerCoordinatorBridgePresenterDelegate,
|
||||
ReactionHistoryCoordinatorBridgePresenterDelegate, CameraPresenterDelegate, MediaPickerCoordinatorBridgePresenterDelegate,
|
||||
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, ThreadsCoordinatorBridgePresenterDelegate>
|
||||
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, ThreadsCoordinatorBridgePresenterDelegate, MXThreadingServiceDelegate>
|
||||
{
|
||||
|
||||
// The preview header
|
||||
@@ -178,6 +178,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
|
||||
// Time to display notification content in the timeline
|
||||
MXTaskProfile *notificationTaskProfile;
|
||||
|
||||
// Reference to thread list bar button item, to update it easily later
|
||||
BadgedBarButtonItem *threadListBarButtonItem;
|
||||
}
|
||||
|
||||
@property (nonatomic, weak) IBOutlet UIView *overlayContainerView;
|
||||
@@ -215,6 +218,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
@property (nonatomic, readwrite) RoomDisplayConfiguration *displayConfiguration;
|
||||
@property (nonatomic) AnalyticsScreenTimer *screenTimer;
|
||||
|
||||
// When layout of the screen changes (e.g. height), we no longer know whether
|
||||
// to autoscroll to the bottom again or not. Instead we need to capture the
|
||||
// scroll state just before the layout change, and restore it after the layout.
|
||||
@property (nonatomic) BOOL shouldScrollToBottomAfterLayout;
|
||||
|
||||
@end
|
||||
|
||||
@implementation RoomViewController
|
||||
@@ -454,6 +462,9 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
|
||||
self.scrollToBottomBadgeLabel.badgeColor = ThemeService.shared.theme.tintColor;
|
||||
|
||||
[self updateThreadListBarButtonBadgeWith:self.mainSession.threadingService];
|
||||
[threadListBarButtonItem updateWithTheme:ThemeService.shared.theme];
|
||||
|
||||
[self setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
@@ -537,6 +548,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
[self cancelEventSelection];
|
||||
}
|
||||
}
|
||||
[self cancelEventHighlight];
|
||||
|
||||
// Hide preview header to restore navigation bar settings
|
||||
[self showPreviewHeader:NO];
|
||||
@@ -650,6 +662,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
[self.screenTimer stop];
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews {
|
||||
[super viewWillLayoutSubviews];
|
||||
self.shouldScrollToBottomAfterLayout = self.isBubblesTableScrollViewAtTheBottom;
|
||||
}
|
||||
|
||||
- (void)viewDidLayoutSubviews
|
||||
{
|
||||
[super viewDidLayoutSubviews];
|
||||
@@ -715,9 +732,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
self.edgesForExtendedLayout = UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight;
|
||||
}
|
||||
|
||||
// stay at the bottom if already was
|
||||
if (self.isBubblesTableScrollViewAtTheBottom)
|
||||
// re-scroll to the bottom, if at bottom before the most recent layout
|
||||
if (self.shouldScrollToBottomAfterLayout)
|
||||
{
|
||||
self.shouldScrollToBottomAfterLayout = NO;
|
||||
[self scrollBubblesTableViewToBottomAnimated:NO];
|
||||
}
|
||||
|
||||
@@ -889,6 +907,21 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
|
||||
#pragma mark - Override MXKRoomViewController
|
||||
|
||||
- (void)addMatrixSession:(MXSession *)mxSession
|
||||
{
|
||||
[super addMatrixSession:mxSession];
|
||||
|
||||
[mxSession.threadingService addDelegate:self];
|
||||
[self updateThreadListBarButtonBadgeWith:mxSession.threadingService];
|
||||
}
|
||||
|
||||
- (void)removeMatrixSession:(MXSession *)mxSession
|
||||
{
|
||||
[mxSession.threadingService removeDelegate:self];
|
||||
|
||||
[super removeMatrixSession:mxSession];
|
||||
}
|
||||
|
||||
- (void)onMatrixSessionChange
|
||||
{
|
||||
[super onMatrixSessionChange];
|
||||
@@ -1416,15 +1449,20 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
return item;
|
||||
}
|
||||
|
||||
- (UIBarButtonItem *)threadListBarButtonItem
|
||||
- (BadgedBarButtonItem *)threadListBarButtonItem
|
||||
{
|
||||
UIButton *button = [UIButton new];
|
||||
UIImage *icon = [[UIImage imageNamed:@"threads_icon"] vc_resizedWith:CGSizeMake(21, 21)];
|
||||
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:icon
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(onThreadListTapped:)];
|
||||
item.accessibilityLabel = [VectorL10n roomAccessibilityThreads];
|
||||
return item;
|
||||
button.contentEdgeInsets = UIEdgeInsetsMake(4, 8, 4, 8);
|
||||
[button setImage:icon
|
||||
forState:UIControlStateNormal];
|
||||
[button addTarget:self
|
||||
action:@selector(onThreadListTapped:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
button.accessibilityLabel = [VectorL10n roomAccessibilityThreads];
|
||||
|
||||
return [[BadgedBarButtonItem alloc] initWithBaseButton:button
|
||||
theme:ThemeService.shared.theme];
|
||||
}
|
||||
|
||||
- (void)setupRemoveJitsiWidgetRemoveView
|
||||
@@ -1664,14 +1702,20 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
if (self.roomDataSource.threadId)
|
||||
{
|
||||
// in a thread
|
||||
if (rightBarButtonItems == nil)
|
||||
{
|
||||
rightBarButtonItems = [NSMutableArray new];
|
||||
}
|
||||
UIBarButtonItem *itemThreadMore = [self threadMoreBarButtonItem];
|
||||
[rightBarButtonItems insertObject:itemThreadMore atIndex:0];
|
||||
}
|
||||
else
|
||||
{
|
||||
// in a regular timeline
|
||||
UIBarButtonItem *itemThreadList = [self threadListBarButtonItem];
|
||||
BadgedBarButtonItem *itemThreadList = [self threadListBarButtonItem];
|
||||
[rightBarButtonItems insertObject:itemThreadList atIndex:0];
|
||||
threadListBarButtonItem = itemThreadList;
|
||||
[self updateThreadListBarButtonBadgeWith:self.mainSession.threadingService];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3415,9 +3459,15 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
|
||||
[self cancelEventSelection];
|
||||
|
||||
NSArray *activityItems = @[selectedComponent.textMessage];
|
||||
UIActivityViewController *activityViewController = nil;
|
||||
if (selectedEvent.location) {
|
||||
activityViewController = [self.delegate roomViewController:self locationShareActivityViewControllerForEvent:selectedEvent];
|
||||
}
|
||||
|
||||
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
|
||||
if (activityViewController == nil) {
|
||||
NSArray *activityItems = @[selectedComponent.textMessage];
|
||||
activityViewController = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
|
||||
}
|
||||
|
||||
if (activityViewController)
|
||||
{
|
||||
@@ -4625,24 +4675,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
[super scrollViewWillBeginDragging:scrollView];
|
||||
}
|
||||
|
||||
// if data source is highlighting an event, dismiss the highlight when user drags the table view
|
||||
if (customizedRoomDataSource.highlightedEventId)
|
||||
{
|
||||
NSInteger row = [self.roomDataSource indexOfCellDataWithEventId:customizedRoomDataSource.highlightedEventId];
|
||||
if (row == NSNotFound)
|
||||
{
|
||||
customizedRoomDataSource.highlightedEventId = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
|
||||
if ([[self.bubblesTableView indexPathsForVisibleRows] containsObject:indexPath])
|
||||
{
|
||||
customizedRoomDataSource.highlightedEventId = nil;
|
||||
[self.bubblesTableView reloadRowsAtIndexPaths:@[indexPath]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
}
|
||||
[self cancelEventHighlight];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
|
||||
@@ -4848,7 +4881,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
if (typingNotifListener)
|
||||
{
|
||||
MXWeakify(self);
|
||||
[self.roomDataSource.room liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
[self.roomDataSource.room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[liveTimeline removeListener:self->typingNotifListener];
|
||||
@@ -5195,7 +5228,14 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
// Retrieve the unread messages count
|
||||
NSUInteger unreadCount = self.roomDataSource.room.summary.localUnreadEventCount;
|
||||
|
||||
self.scrollToBottomBadgeLabel.text = unreadCount ? [NSString stringWithFormat:@"%lu", unreadCount] : nil;
|
||||
if (!self.roomDataSource.threadId)
|
||||
{
|
||||
self.scrollToBottomBadgeLabel.text = unreadCount ? [NSString stringWithFormat:@"%lu", unreadCount] : nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.scrollToBottomBadgeLabel.text = nil;
|
||||
}
|
||||
self.scrollToBottomHidden = NO;
|
||||
}
|
||||
else
|
||||
@@ -5243,33 +5283,58 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
self.updateRoomReadMarker = NO;
|
||||
|
||||
[self scrollBubblesTableViewToBottomAnimated:YES];
|
||||
|
||||
[self cancelEventHighlight];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch back to the room live timeline managed by MXKRoomDataSourceManager
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mainSession];
|
||||
|
||||
MXWeakify(self);
|
||||
[roomDataSourceManager roomDataSourceForRoom:self.roomDataSource.roomId create:YES onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
|
||||
void(^continueBlock)(MXKRoomDataSource *, BOOL) = ^(MXKRoomDataSource *roomDataSource, BOOL hasRoomDataSourceOwnership){
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
|
||||
[roomDataSource finalizeInitialization];
|
||||
|
||||
// Scroll to bottom the bubble history on the display refresh.
|
||||
self->shouldScrollToBottomOnTableRefresh = YES;
|
||||
|
||||
|
||||
[self displayRoom:roomDataSource];
|
||||
|
||||
// The room view controller do not have here the data source ownership.
|
||||
self.hasRoomDataSourceOwnership = NO;
|
||||
|
||||
|
||||
// Set the room view controller has the data source ownership here.
|
||||
self.hasRoomDataSourceOwnership = hasRoomDataSourceOwnership;
|
||||
|
||||
[self refreshActivitiesViewDisplay];
|
||||
[self refreshJumpToLastUnreadBannerDisplay];
|
||||
|
||||
|
||||
if (self.saveProgressTextInput)
|
||||
{
|
||||
// Restore the potential message partially typed before jump to last unread messages.
|
||||
self.inputToolbarView.textMessage = roomDataSource.partialTextMessage;
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
if (self.roomDataSource.threadId)
|
||||
{
|
||||
[ThreadDataSource loadRoomDataSourceWithRoomId:self.roomDataSource.roomId
|
||||
initialEventId:nil
|
||||
threadId:self.roomDataSource.threadId
|
||||
andMatrixSession:self.mainSession
|
||||
onComplete:^(ThreadDataSource *threadDataSource)
|
||||
{
|
||||
continueBlock(threadDataSource, YES);
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Switch back to the room live timeline managed by MXKRoomDataSourceManager
|
||||
MXKRoomDataSourceManager *roomDataSourceManager = [MXKRoomDataSourceManager sharedManagerForMatrixSession:self.mainSession];
|
||||
|
||||
[roomDataSourceManager roomDataSourceForRoom:self.roomDataSource.roomId
|
||||
create:YES
|
||||
onComplete:^(MXKRoomDataSource *roomDataSource) {
|
||||
continueBlock(roomDataSource, NO);
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6531,6 +6596,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
andMatrixSession:self.roomDataSource.mxSession
|
||||
onComplete:^(RoomDataSource *roomDataSource) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
[roomDataSource finalizeInitialization];
|
||||
[self stopActivityIndicator];
|
||||
roomDataSource.markTimelineInitialEvent = YES;
|
||||
[self displayRoom:roomDataSource];
|
||||
@@ -6550,7 +6616,10 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
if ([[self.bubblesTableView indexPathsForVisibleRows] containsObject:indexPath])
|
||||
{
|
||||
[self.bubblesTableView reloadRowsAtIndexPaths:@[indexPath]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
withRowAnimation:UITableViewRowAnimationNone];
|
||||
[self.bubblesTableView scrollToRowAtIndexPath:indexPath
|
||||
atScrollPosition:UITableViewScrollPositionMiddle
|
||||
animated:YES];
|
||||
}
|
||||
else if ([self.bubblesTableView vc_hasIndexPath:indexPath])
|
||||
{
|
||||
@@ -6564,6 +6633,67 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelEventHighlight
|
||||
{
|
||||
// if data source is highlighting an event, dismiss the highlight when user dragges the table view
|
||||
if (customizedRoomDataSource.highlightedEventId)
|
||||
{
|
||||
NSInteger row = [self.roomDataSource indexOfCellDataWithEventId:customizedRoomDataSource.highlightedEventId];
|
||||
if (row == NSNotFound)
|
||||
{
|
||||
customizedRoomDataSource.highlightedEventId = nil;
|
||||
return;
|
||||
}
|
||||
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
|
||||
if ([[self.bubblesTableView indexPathsForVisibleRows] containsObject:indexPath])
|
||||
{
|
||||
customizedRoomDataSource.highlightedEventId = nil;
|
||||
[self.bubblesTableView reloadRowsAtIndexPaths:@[indexPath]
|
||||
withRowAnimation:UITableViewRowAnimationAutomatic];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateThreadListBarButtonBadgeWith:(MXThreadingService *)service
|
||||
{
|
||||
if (!threadListBarButtonItem || !service)
|
||||
{
|
||||
// there is no thread list bar button, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
MXThreadNotificationsCount *notificationsCount = [service notificationsCountForRoom:self.roomDataSource.roomId];
|
||||
|
||||
if (notificationsCount.numberOfHighlightedThreads > 0)
|
||||
{
|
||||
threadListBarButtonItem.badgeText = [self threadListBadgeTextFor:notificationsCount.numberOfHighlightedThreads];
|
||||
threadListBarButtonItem.badgeBackgroundColor = ThemeService.shared.theme.colors.alert;
|
||||
}
|
||||
else if (notificationsCount.numberOfNotifiedThreads > 0)
|
||||
{
|
||||
threadListBarButtonItem.badgeText = [self threadListBadgeTextFor:notificationsCount.numberOfNotifiedThreads];
|
||||
threadListBarButtonItem.badgeBackgroundColor = ThemeService.shared.theme.noticeSecondaryColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove badge
|
||||
threadListBarButtonItem.badgeText = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)threadListBadgeTextFor:(NSUInteger)numberOfThreads
|
||||
{
|
||||
if (numberOfThreads < 100)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%tu", numberOfThreads];
|
||||
}
|
||||
else
|
||||
{
|
||||
return @"···";
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - RoomContextualMenuViewControllerDelegate
|
||||
|
||||
- (void)roomContextualMenuViewControllerDidTapBackgroundOverlay:(RoomContextualMenuViewController *)viewController
|
||||
@@ -6988,4 +7118,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
|
||||
self.threadsBridgePresenter = nil;
|
||||
}
|
||||
|
||||
#pragma mark - MXThreadingServiceDelegate
|
||||
|
||||
- (void)threadingServiceDidUpdateThreads:(MXThreadingService *)service
|
||||
{
|
||||
[self updateThreadListBarButtonBadgeWith:service];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -57,33 +57,69 @@
|
||||
{
|
||||
// Prepare text font used to highlight the search pattern.
|
||||
UIFont *patternFont = [roomDataSource.eventFormatter bingTextFont];
|
||||
|
||||
dispatch_group_t group = dispatch_group_create();
|
||||
|
||||
// Convert the HS results into `RoomViewController` cells
|
||||
for (MXSearchResult *result in roomEventResults.results)
|
||||
{
|
||||
// Let the `RoomViewController` ecosystem do the job
|
||||
// The search result contains only room message events, no state events.
|
||||
// Thus, passing the current room state is not a huge problem. Only
|
||||
// the user display name and his avatar may be wrong.
|
||||
RoomBubbleCellData *cellData = [[RoomBubbleCellData alloc] initWithEvent:result.result andRoomState:roomDataSource.roomState andRoomDataSource:roomDataSource];
|
||||
if (cellData)
|
||||
dispatch_group_enter(group);
|
||||
|
||||
void(^continueBlock)(void) = ^{
|
||||
// Let the `RoomViewController` ecosystem do the job
|
||||
// The search result contains only room message events, no state events.
|
||||
// Thus, passing the current room state is not a huge problem. Only
|
||||
// the user display name and his avatar may be wrong.
|
||||
RoomBubbleCellData *cellData = [[RoomBubbleCellData alloc] initWithEvent:result.result andRoomState:self->roomDataSource.roomState andRoomDataSource:self->roomDataSource];
|
||||
if (cellData)
|
||||
{
|
||||
// Highlight the search pattern
|
||||
[cellData highlightPatternInTextMessage:self.searchText
|
||||
withBackgroundColor:ThemeService.shared.theme.searchResultHighlightColor
|
||||
foregroundColor:ThemeService.shared.theme.textPrimaryColor
|
||||
andFont:patternFont];
|
||||
|
||||
// Use profile information as data to display
|
||||
MXSearchUserProfile *userProfile = result.context.profileInfo[result.result.sender];
|
||||
cellData.senderDisplayName = userProfile.displayName;
|
||||
cellData.senderAvatarUrl = userProfile.avatarUrl;
|
||||
|
||||
[self->cellDataArray insertObject:cellData atIndex:0];
|
||||
}
|
||||
|
||||
dispatch_group_leave(group);
|
||||
};
|
||||
|
||||
if (RiotSettings.shared.enableThreads)
|
||||
{
|
||||
// Highlight the search pattern
|
||||
[cellData highlightPatternInTextMessage:self.searchText
|
||||
withBackgroundColor:[UIColor clearColor]
|
||||
foregroundColor:ThemeService.shared.theme.tintColor
|
||||
andFont:patternFont];
|
||||
|
||||
// Use profile information as data to display
|
||||
MXSearchUserProfile *userProfile = result.context.profileInfo[result.result.sender];
|
||||
cellData.senderDisplayName = userProfile.displayName;
|
||||
cellData.senderAvatarUrl = userProfile.avatarUrl;
|
||||
|
||||
[cellDataArray insertObject:cellData atIndex:0];
|
||||
if (result.result.isInThread)
|
||||
{
|
||||
continueBlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
[roomDataSource.room liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
[liveTimeline paginate:NSUIntegerMax
|
||||
direction:MXTimelineDirectionBackwards
|
||||
onlyFromStore:YES
|
||||
complete:^{
|
||||
[liveTimeline resetPagination];
|
||||
continueBlock();
|
||||
} failure:^(NSError * _Nonnull error) {
|
||||
continueBlock();
|
||||
}];
|
||||
}];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
continueBlock();
|
||||
}
|
||||
}
|
||||
|
||||
onComplete();
|
||||
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
|
||||
onComplete();
|
||||
});
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
|
||||
@@ -93,6 +93,9 @@
|
||||
UIImage *image = [MXKTools paintImage:backgroundImageView.image withColor:ThemeService.shared.theme.matrixSearchBackgroundImageTintColor];
|
||||
backgroundImageView.image = image;
|
||||
}
|
||||
|
||||
// Match the search bar color to the navigation bar color as it extends slightly outside the frame.
|
||||
self.searchBar.backgroundColor = ThemeService.shared.theme.baseColor;
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
@@ -155,15 +158,18 @@
|
||||
- (void)selectEvent:(MXEvent *)event
|
||||
{
|
||||
ThreadParameters *threadParameters = nil;
|
||||
if (event.threadId)
|
||||
if (RiotSettings.shared.enableThreads)
|
||||
{
|
||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
|
||||
stackRoomScreen:NO];
|
||||
}
|
||||
else if ([self.mainSession.threadingService isEventThreadRoot:event])
|
||||
{
|
||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
|
||||
stackRoomScreen:NO];
|
||||
if (event.threadId)
|
||||
{
|
||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.threadId
|
||||
stackRoomScreen:NO];
|
||||
}
|
||||
else if ([self.mainSession.threadingService isEventThreadRoot:event])
|
||||
{
|
||||
threadParameters = [[ThreadParameters alloc] initWithThreadId:event.eventId
|
||||
stackRoomScreen:NO];
|
||||
}
|
||||
}
|
||||
|
||||
ScreenPresentationParameters *screenParameters = [[ScreenPresentationParameters alloc] initWithRestoreInitialDisplay:NO
|
||||
|
||||
@@ -429,7 +429,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
if (extraEventsListener)
|
||||
{
|
||||
MXWeakify(self);
|
||||
[mxRoom liveTimeline:^(MXEventTimeline *liveTimeline) {
|
||||
[mxRoom liveTimeline:^(id<MXEventTimeline> liveTimeline) {
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
[liveTimeline removeListener:self->extraEventsListener];
|
||||
|
||||
@@ -37,6 +37,8 @@ class LocationBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable
|
||||
|
||||
let location = CLLocationCoordinate2D(latitude: locationContent.latitude, longitude: locationContent.longitude)
|
||||
|
||||
let mapStyleURL = bubbleData.mxSession.vc_homeserverConfiguration().tileServer.mapStyleURL
|
||||
|
||||
if locationContent.assetType == .user {
|
||||
let avatarViewData = AvatarViewData(matrixItemId: bubbleData.senderId,
|
||||
displayName: bubbleData.senderDisplayName,
|
||||
@@ -44,9 +46,9 @@ class LocationBubbleCell: SizableBaseBubbleCell, BubbleCellReactionsDisplayable
|
||||
mediaManager: bubbleData.mxSession.mediaManager,
|
||||
fallbackImage: .matrixItem(bubbleData.senderId, bubbleData.senderDisplayName))
|
||||
|
||||
locationView.displayLocation(location, userAvatarData: avatarViewData)
|
||||
locationView.displayLocation(location, userAvatarData: avatarViewData, mapStyleURL: mapStyleURL)
|
||||
} else {
|
||||
locationView.displayLocation(location)
|
||||
locationView.displayLocation(location, mapStyleURL: mapStyleURL)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9wW-1f-f69" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9wW-1f-f69" customClass="UserAvatarView" customModule="Riot" customModuleProvider="target">
|
||||
<rect key="frame" x="44" y="4" width="24" height="24"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
|
||||
Reference in New Issue
Block a user