Fix review remarks

This commit is contained in:
ismailgulek 2022-01-25 23:59:19 +03:00
parent f603c2408c
commit c23a69c338
No known key found for this signature in database
GPG key ID: E96336D42D9470A9
36 changed files with 205 additions and 223 deletions

View file

@ -434,7 +434,7 @@ Tap the + to start adding people.";
"room_join_group_call" = "Join";
"room_no_privileges_to_create_group_call" = "You need to be an admin or a moderator to start a call.";
// MARK: Threads
// MARK: Threads
"room_thread_title" = "Thread";
"thread_copy_link_to_thread" = "Copy link to thread";
"threads_title" = "Threads";

View file

@ -1380,7 +1380,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
RoomNavigationParameters *roomNavigationParameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:account.mxSession
threadParameters:threadParameters
threadParameters:threadParameters
presentationParameters:screenPresentationParameters];
[self showRoomWithParameters:roomNavigationParameters];
@ -2914,7 +2914,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:mxSession
threadParameters:nil
threadParameters:nil
presentationParameters:presentationParameters];
[self showRoomWithParameters:parameters];

View file

@ -875,7 +875,7 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:nil
mxSession:matrixSession
threadParameters:nil
threadParameters:nil
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters completion:^{

View file

@ -157,7 +157,7 @@
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:session
threadParameters:nil
threadParameters:nil
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters];

View file

@ -164,7 +164,7 @@
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:eventId
mxSession:session
threadParameters:nil
threadParameters:nil
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters];

View file

@ -248,7 +248,7 @@
RoomNavigationParameters *parameters = [[RoomNavigationParameters alloc] initWithRoomId:roomId
eventId:nil
mxSession:mxSession
threadParameters:nil
threadParameters:nil
presentationParameters:presentationParameters];
[[AppDelegate theDelegate] showRoomWithParameters:parameters];
}

View file

@ -274,7 +274,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
@param roomId the id of the room to get data from.
@param initialEventId the id of the event where to start the timeline.
@param threadId the id of the thread to load.
@param threadId the id of the thread to load. If provided, thread data source will be loaded from the room specified with `roomId`.
@param mxSession the Matrix session to get data from.
@param onComplete a block providing the newly created instance.
*/
@ -316,7 +316,7 @@ extern NSString *const kMXKRoomDataSourceTimelineErrorErrorKey;
@param roomId the id of the room to get data from.
@param initialEventId the id of the event where to start the timeline.
@param threadId the id of the thread to initialize.
@param threadId the id of the thread to initialize. If provided, thread data source will be initialized from the room specified with `roomId`.
@param mxSession the Matrix session to get data from.
@return the newly created instance.
*/

View file

@ -1458,7 +1458,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
paginationRequest = [_timeline paginate:numItems
direction:direction
onlyFromStore:onlyFromStore
// threadId:_threadId
complete:^{
MXStrongifyAndReturnIfNil(self);
@ -1526,7 +1525,6 @@ typedef NS_ENUM (NSUInteger, MXKRoomDataSourceError) {
secondaryPaginationRequest = [_secondaryTimeline paginate:numItems
direction:direction
onlyFromStore:onlyFromStore
// threadId:_threadId
complete:^{
MXStrongifyAndReturnIfNil(self);

View file

@ -113,14 +113,14 @@
@protocol RoomDataSourceDelegate <MXKDataSourceDelegate>
/**
Called when the room's encryption trust level did updated.
Called when the room's encryption trust level did update.
@param roomDataSource room data source instance
*/
- (void)roomDataSourceDidUpdateEncryptionTrustLevel:(RoomDataSource * _Nonnull)roomDataSource;
/**
Called when a thread summary view
Called when a thread summary view is tapped.
@param roomDataSource room data source instance
*/

View file

@ -464,6 +464,7 @@ const CGFloat kTypingCellHeight = 24;
{
threadSummaryView = [[ThreadSummaryView alloc] initWithThread:component.thread];
threadSummaryView.delegate = self;
threadSummaryView.tag = index;
[temporaryViews addObject:threadSummaryView];
UIView *upperDecorationView = reactionsView ?: urlPreviewView;

View file

@ -134,7 +134,7 @@ final class RoomCoordinator: NSObject, RoomCoordinatorProtocol {
self.selectedEventId = eventId
if self.hasStartedOnce {
self.roomViewController.highlightEvent(eventId, completion: completion)
self.roomViewController.highlightAndDisplayEvent(eventId, completion: completion)
} else {
self.start(withCompletion: completion)
}

View file

@ -106,7 +106,7 @@ extern NSNotificationName const RoomGroupCallTileTappedNotification;
@param eventId Identifier of the event to be highlighted.
@param completion Completion block to be called at the end of process. Optional.
*/
- (void)highlightEvent:(NSString *)eventId completion:(nullable void (^)(void))completion;
- (void)highlightAndDisplayEvent:(NSString *)eventId completion:(nullable void (^)(void))completion;
/**
Creates and returns a new `RoomViewController` object.

View file

@ -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, RoomCoordinatorBridgePresenterDelegate, ThreadsCoordinatorBridgePresenterDelegate>
RoomDataSourceDelegate, RoomCreationModalCoordinatorBridgePresenterDelegate, RoomInfoCoordinatorBridgePresenterDelegate, DialpadViewControllerDelegate, RemoveJitsiWidgetViewDelegate, VoiceMessageControllerDelegate, SpaceDetailPresenterDelegate, UserSuggestionCoordinatorBridgeDelegate, ThreadsCoordinatorBridgePresenterDelegate>
{
// The preview header
@ -197,9 +197,8 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
@property (nonatomic, strong) RoomMessageURLParser *roomMessageURLParser;
@property (nonatomic, strong) RoomCreationModalCoordinatorBridgePresenter *roomCreationModalCoordinatorBridgePresenter;
@property (nonatomic, strong) RoomInfoCoordinatorBridgePresenter *roomInfoCoordinatorBridgePresenter;
@property (nonatomic, strong) RoomCoordinatorBridgePresenter *threadBridgePresenter;
@property (nonatomic, strong) CustomSizedPresentationController *customSizedPresentationController;
@property (nonatomic, strong) ThreadsCoordinatorBridgePresenter *threadsCoordinatorBridgePresenter;
@property (nonatomic, strong) ThreadsCoordinatorBridgePresenter *threadsBridgePresenter;
@property (nonatomic, getter=isActivitiesViewExpanded) BOOL activitiesViewExpanded;
@property (nonatomic, getter=isScrollToBottomHidden) BOOL scrollToBottomHidden;
@property (nonatomic, getter=isMissedDiscussionsBadgeHidden) BOOL missedDiscussionsBadgeHidden;
@ -4341,10 +4340,11 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (IBAction)onThreadListTapped:(id)sender
{
self.threadsCoordinatorBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
roomId:self.roomDataSource.roomId];
self.threadsCoordinatorBridgePresenter.delegate = self;
[self.threadsCoordinatorBridgePresenter pushFrom:self.navigationController animated:YES];
self.threadsBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
roomId:self.roomDataSource.roomId
threadId:nil];
self.threadsBridgePresenter.delegate = self;
[self.threadsBridgePresenter pushFrom:self.navigationController animated:YES];
}
- (IBAction)onIntegrationsPressed:(id)sender
@ -4473,7 +4473,7 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[super scrollViewWillBeginDragging:scrollView];
}
// if data source is highlighting an event, dismiss the highlight when user dragges the table view
// 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];
@ -6352,25 +6352,20 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
- (void)openThreadWithId:(NSString *)threadId
{
if (self.threadBridgePresenter)
if (self.threadsBridgePresenter)
{
[self.threadBridgePresenter dismissWithAnimated:YES completion:nil];
self.threadBridgePresenter = nil;
[self.threadsBridgePresenter dismissWithAnimated:YES completion:nil];
self.threadsBridgePresenter = nil;
}
RoomDisplayConfiguration *configuration = RoomDisplayConfiguration.forThreads;
RoomCoordinatorBridgePresenterParameters *parameters = [[RoomCoordinatorBridgePresenterParameters alloc] initWithSession:self.mainSession
roomId:self.roomDataSource.roomId
eventId:nil
threadId:threadId
displayConfiguration:configuration
previewData:nil];
self.threadBridgePresenter = [[RoomCoordinatorBridgePresenter alloc] initWithParameters:parameters];
self.threadBridgePresenter.delegate = self;
[self.threadBridgePresenter pushFrom:self.navigationController animated:YES];
self.threadsBridgePresenter = [[ThreadsCoordinatorBridgePresenter alloc] initWithSession:self.mainSession
roomId:self.roomDataSource.roomId
threadId:threadId];
self.threadsBridgePresenter.delegate = self;
[self.threadsBridgePresenter pushFrom:self.navigationController animated:YES];
}
- (void)highlightEvent:(NSString *)eventId completion:(void (^)(void))completion
- (void)highlightAndDisplayEvent:(NSString *)eventId completion:(void (^)(void))completion
{
NSInteger row = [self.roomDataSource indexOfCellDataWithEventId:eventId];
if (row == NSNotFound)
@ -6816,66 +6811,29 @@ const NSTimeInterval kResizeComposerAnimationDuration = .05;
[self mention:member];
}
#pragma mark - RoomCoordinatorBridgePresenterDelegate
- (void)roomCoordinatorBridgePresenterDidLeaveRoom:(RoomCoordinatorBridgePresenter *)bridgePresenter
{
}
- (void)roomCoordinatorBridgePresenterDidCancelRoomPreview:(RoomCoordinatorBridgePresenter *)bridgePresenter
{
}
- (void)roomCoordinatorBridgePresenter:(RoomCoordinatorBridgePresenter *)bridgePresenter
didSelectRoomWithId:(NSString *)roomId
eventId:(NSString*)eventId
{
if (bridgePresenter == self.threadBridgePresenter && [roomId isEqualToString:self.roomDataSource.roomId] && eventId)
{
// thread view wants to highlight an event in the timeline
// dismiss thread view first
MXWeakify(self);
[self.threadBridgePresenter dismissWithAnimated:YES completion:^{
MXStrongifyAndReturnIfNil(self);
[self highlightEvent:eventId completion:nil];
}];
}
}
- (void)roomCoordinatorBridgePresenterDidDismissInteractively:(RoomCoordinatorBridgePresenter *)bridgePresenter
{
if (bridgePresenter == self.threadBridgePresenter)
{
self.threadBridgePresenter = nil;
}
}
#pragma mark - ThreadsCoordinatorBridgePresenterDelegate
- (void)threadsCoordinatorBridgePresenterDelegateDidComplete:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
self.threadsCoordinatorBridgePresenter = nil;
self.threadsBridgePresenter = nil;
}
- (void)threadsCoordinatorBridgePresenterDelegateDidSelect:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter roomId:(NSString *)roomId eventId:(NSString *)eventId
{
MXWeakify(self);
[self.threadsCoordinatorBridgePresenter dismissWithAnimated:YES completion:^{
[self.threadsBridgePresenter dismissWithAnimated:YES completion:^{
MXStrongifyAndReturnIfNil(self);
if (eventId)
{
[self highlightEvent:eventId completion:nil];
[self highlightAndDisplayEvent:eventId completion:nil];
}
}];
}
- (void)threadsCoordinatorBridgePresenterDidDismissInteractively:(ThreadsCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
self.threadsCoordinatorBridgePresenter = nil;
self.threadsBridgePresenter = nil;
}
@end

View file

@ -16,8 +16,8 @@
import Foundation
struct ThreadSummaryViewModel {
var numberOfReplies: Int
var lastMessageSenderAvatar: AvatarViewDataProtocol?
var lastMessageText: String?
struct ThreadSummaryModel {
let numberOfReplies: Int
let lastMessageSenderAvatar: AvatarViewDataProtocol?
let lastMessageText: String?
}

View file

@ -37,7 +37,7 @@ class ThreadSummaryView: UIView {
@IBOutlet private weak var lastMessageAvatarView: UserAvatarView!
@IBOutlet private weak var lastMessageContentLabel: UILabel!
private(set) var thread: MXThread!
private(set) var thread: MXThread?
private lazy var tapGestureRecognizer: UITapGestureRecognizer = {
return UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
@ -57,7 +57,7 @@ class ThreadSummaryView: UIView {
configure()
}
static func contentViewHeight(forThread thread: MXThread, fitting maxWidth: CGFloat) -> CGFloat {
static func contentViewHeight(forThread thread: MXThread?, fitting maxWidth: CGFloat) -> CGFloat {
return Constants.viewHeight
}
@ -66,7 +66,7 @@ class ThreadSummaryView: UIView {
loadNibContent()
}
@nonobjc func configure(withViewModel viewModel: ThreadSummaryViewModel) {
@nonobjc func configure(withViewModel viewModel: ThreadSummaryModel) {
numberOfRepliesLabel.text = String(viewModel.numberOfReplies)
if let avatar = viewModel.lastMessageSenderAvatar {
lastMessageAvatarView.fill(with: avatar)
@ -105,7 +105,7 @@ class ThreadSummaryView: UIView {
let formatterError = UnsafeMutablePointer<MXKEventFormatterError>.allocate(capacity: 1)
let lastMessageText = eventFormatter.string(from: lastMessage, with: roomState, error: formatterError)
let viewModel = ThreadSummaryViewModel(numberOfReplies: thread.numberOfReplies,
let viewModel = ThreadSummaryModel(numberOfReplies: thread.numberOfReplies,
lastMessageSenderAvatar: avatarViewData,
lastMessageText: lastMessageText)
self.configure(withViewModel: viewModel)
@ -121,8 +121,6 @@ class ThreadSummaryView: UIView {
}
}
// extension ThreadSummaryView: NibLoadable {}
extension ThreadSummaryView: NibOwnerLoadable {}
extension ThreadSummaryView: Themable {

View file

@ -16,12 +16,12 @@
import Foundation
struct ThreadRoomTitleViewModel {
var roomAvatar: AvatarViewDataProtocol?
var roomEncryptionBadge: UIImage?
var roomDisplayName: String?
struct ThreadRoomTitleModel {
let roomAvatar: AvatarViewDataProtocol?
let roomEncryptionBadge: UIImage?
let roomDisplayName: String?
static let empty = ThreadRoomTitleViewModel(roomAvatar: nil,
roomEncryptionBadge: nil,
roomDisplayName: nil)
static let empty = ThreadRoomTitleModel(roomAvatar: nil,
roomEncryptionBadge: nil,
roomDisplayName: nil)
}

View file

@ -44,7 +44,7 @@ class ThreadRoomTitleView: RoomTitleView {
// MARK: - Methods
func configure(withViewModel viewModel: ThreadRoomTitleViewModel) {
func configure(withViewModel viewModel: ThreadRoomTitleModel) {
if let avatarViewData = viewModel.roomAvatar {
roomAvatarView.fill(with: avatarViewData)
} else {
@ -87,9 +87,9 @@ class ThreadRoomTitleView: RoomTitleView {
encrpytionBadge = nil
}
let viewModel = ThreadRoomTitleViewModel(roomAvatar: avatarViewData,
roomEncryptionBadge: encrpytionBadge,
roomDisplayName: room.displayName)
let viewModel = ThreadRoomTitleModel(roomAvatar: avatarViewData,
roomEncryptionBadge: encrpytionBadge,
roomDisplayName: room.displayName)
configure(withViewModel: viewModel)
}

View file

@ -363,13 +363,13 @@ extension SplitViewCoordinator: SplitViewMasterPresentableDelegate {
detailNavigationRouter.push(detailPresentable, animated: true, popCompletion: popCompletion)
}
func splitViewMasterPresentable(_ presentable: Presentable, wantsToReplaceDetailsWith modules: [PresentableModule]) {
func splitViewMasterPresentable(_ presentable: Presentable, wantsToReplaceDetailsWith modules: [NavigationModule]) {
MXLog.debug("[SplitViewCoordinator] splitViewMasterPresentable: \(presentable) wantsToReplaceDetailsWith modules: \(modules)")
self.detailNavigationRouter?.setModules(modules, animated: true)
}
func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack modules: [PresentableModule]) {
func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack modules: [NavigationModule]) {
guard let detailNavigationRouter = self.detailNavigationRouter else {
MXLog.warning("[SplitViewCoordinator] Failed to stack \(modules) because detailNavigationRouter is nil")
return

View file

@ -28,10 +28,10 @@ protocol SplitViewMasterPresentableDelegate: AnyObject {
func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack detailPresentable: Presentable, popCompletion: (() -> Void)?)
/// Replace split view detail with the given modules
func splitViewMasterPresentable(_ presentable: Presentable, wantsToReplaceDetailsWith modules: [PresentableModule])
func splitViewMasterPresentable(_ presentable: Presentable, wantsToReplaceDetailsWith modules: [NavigationModule])
/// Stack modules on the existing split view detail stack
func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack modules: [PresentableModule])
func splitViewMasterPresentable(_ presentable: Presentable, wantsToStack modules: [NavigationModule])
/// Pop to module on the existing split view detail stack
func splitViewMasterPresentable(_ presentable: Presentable, wantsToPopTo module: Presentable)

View file

@ -395,57 +395,8 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
private func showRoom(withNavigationParameters roomNavigationParameters: RoomNavigationParameters, completion: (() -> Void)?) {
if let threadParameters = roomNavigationParameters.threadParameters, threadParameters.stackRoomScreen {
self.activityIndicatorPresenter.presentActivityIndicator(on: toPresentable().view, animated: false)
let dispatchGroup = DispatchGroup()
// create room coordinator
let roomCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
session: roomNavigationParameters.mxSession,
roomId: roomNavigationParameters.roomId,
eventId: nil,
threadId: nil)
dispatchGroup.enter()
let roomCoordinator = RoomCoordinator(parameters: roomCoordinatorParameters)
roomCoordinator.delegate = self
roomCoordinator.start {
dispatchGroup.leave()
}
self.add(childCoordinator: roomCoordinator)
// create thread coordinator
let threadCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
session: roomNavigationParameters.mxSession,
roomId: roomNavigationParameters.roomId,
eventId: roomNavigationParameters.eventId,
threadId: roomNavigationParameters.threadParameters?.threadId)
dispatchGroup.enter()
let threadCoordinator = RoomCoordinator(parameters: threadCoordinatorParameters)
threadCoordinator.delegate = self
threadCoordinator.start {
dispatchGroup.leave()
}
self.add(childCoordinator: threadCoordinator)
dispatchGroup.notify(queue: .main) { [weak self] in
guard let self = self else { return }
let modules: [PresentableModule] = [
PresentableModule(presentable: roomCoordinator, popCompletion: { [weak self] in
// NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
self?.remove(childCoordinator: roomCoordinator)
}),
PresentableModule(presentable: threadCoordinator, popCompletion: { [weak self] in
// NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
self?.remove(childCoordinator: threadCoordinator)
})
]
self.showSplitViewDetails(with: modules,
stack: roomNavigationParameters.presentationParameters.stackAboveVisibleViews)
self.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true)
}
showRoomAndThread(with: roomNavigationParameters,
completion: completion)
} else {
let roomCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
session: roomNavigationParameters.mxSession,
@ -522,6 +473,63 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
self?.remove(childCoordinator: coordinator)
}
}
private func showRoomAndThread(with roomNavigationParameters: RoomNavigationParameters,
completion: (() -> Void)? = nil) {
self.activityIndicatorPresenter.presentActivityIndicator(on: toPresentable().view, animated: false)
let dispatchGroup = DispatchGroup()
// create room coordinator
let roomCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
session: roomNavigationParameters.mxSession,
roomId: roomNavigationParameters.roomId,
eventId: nil,
threadId: nil)
dispatchGroup.enter()
let roomCoordinator = RoomCoordinator(parameters: roomCoordinatorParameters)
roomCoordinator.delegate = self
roomCoordinator.start {
dispatchGroup.leave()
}
self.add(childCoordinator: roomCoordinator)
// create thread coordinator
let threadCoordinatorParameters = RoomCoordinatorParameters(navigationRouterStore: NavigationRouterStore.shared,
session: roomNavigationParameters.mxSession,
roomId: roomNavigationParameters.roomId,
eventId: roomNavigationParameters.eventId,
threadId: roomNavigationParameters.threadParameters?.threadId)
dispatchGroup.enter()
let threadCoordinator = RoomCoordinator(parameters: threadCoordinatorParameters)
threadCoordinator.delegate = self
threadCoordinator.start {
dispatchGroup.leave()
}
self.add(childCoordinator: threadCoordinator)
dispatchGroup.notify(queue: .main) { [weak self] in
guard let self = self else { return }
let modules: [NavigationModule] = [
NavigationModule(presentable: roomCoordinator, popCompletion: { [weak self] in
// NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
self?.remove(childCoordinator: roomCoordinator)
}),
NavigationModule(presentable: threadCoordinator, popCompletion: { [weak self] in
// NOTE: The RoomDataSource releasing is handled in SplitViewCoordinator
self?.remove(childCoordinator: threadCoordinator)
})
]
self.showSplitViewDetails(with: modules,
stack: roomNavigationParameters.presentationParameters.stackAboveVisibleViews)
self.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true)
completion?()
}
}
// MARK: Split view
@ -544,7 +552,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType {
}
}
private func showSplitViewDetails(with modules: [PresentableModule], stack: Bool) {
private func showSplitViewDetails(with modules: [NavigationModule], stack: Bool) {
if stack {
self.splitViewMasterPresentableDelegate?.splitViewMasterPresentable(self, wantsToStack: modules)
} else {

View file

@ -24,7 +24,7 @@ protocol ThreadListCoordinatorDelegate: AnyObject {
func threadListCoordinatorDidCancel(_ coordinator: ThreadListCoordinatorProtocol)
}
/// `ThreadListCoordinatorProtocol` is a protocol describing a Coordinator that handle xxxxxxx navigation flow.
/// `ThreadListCoordinatorProtocol` is a protocol describing a Coordinator that handle thread list navigation flow.
protocol ThreadListCoordinatorProtocol: Coordinator, Presentable {
var delegate: ThreadListCoordinatorDelegate? { get }
}

View file

@ -20,12 +20,6 @@ import UIKit
final class ThreadListViewController: UIViewController {
// MARK: - Constants
private enum Constants {
static let aConstant: Int = 666
}
// MARK: - Properties
// MARK: Outlets
@ -172,7 +166,7 @@ final class ThreadListViewController: UIViewController {
navigationItem.rightBarButtonItem?.isEnabled = true
}
private func renderEmptyView(withViewModel emptyViewModel: ThreadListEmptyViewModel) {
private func renderEmptyView(withViewModel emptyViewModel: ThreadListEmptyModel) {
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
emptyView.configure(withViewModel: emptyViewModel)
threadsTableView.isHidden = true

View file

@ -83,14 +83,14 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
return threads.count
}
func threadViewModel(at index: Int) -> ThreadViewModel? {
func threadViewModel(at index: Int) -> ThreadModel? {
guard index < threads.count else {
return nil
}
return viewModel(forThread: threads[index])
}
var titleViewModel: ThreadRoomTitleViewModel {
var titleViewModel: ThreadRoomTitleModel {
guard let room = session.room(withRoomId: roomId) else {
return .empty
}
@ -109,33 +109,33 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
encrpytionBadge = nil
}
return ThreadRoomTitleViewModel(roomAvatar: avatarViewData,
roomEncryptionBadge: encrpytionBadge,
roomDisplayName: room.displayName)
return ThreadRoomTitleModel(roomAvatar: avatarViewData,
roomEncryptionBadge: encrpytionBadge,
roomDisplayName: room.displayName)
}
private var emptyViewModel: ThreadListEmptyViewModel {
private var emptyViewModel: ThreadListEmptyModel {
switch selectedFilterType {
case .all:
return ThreadListEmptyViewModel(icon: Asset.Images.roomContextMenuReplyInThread.image,
title: VectorL10n.threadsEmptyTitle,
info: VectorL10n.threadsEmptyInfoAll,
tip: VectorL10n.threadsEmptyTip,
showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
showAllThreadsButtonHidden: true)
return ThreadListEmptyModel(icon: Asset.Images.roomContextMenuReplyInThread.image,
title: VectorL10n.threadsEmptyTitle,
info: VectorL10n.threadsEmptyInfoAll,
tip: VectorL10n.threadsEmptyTip,
showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
showAllThreadsButtonHidden: true)
case .myThreads:
return ThreadListEmptyViewModel(icon: Asset.Images.roomContextMenuReplyInThread.image,
title: VectorL10n.threadsEmptyTitle,
info: VectorL10n.threadsEmptyInfoMy,
tip: VectorL10n.threadsEmptyTip,
showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
showAllThreadsButtonHidden: false)
return ThreadListEmptyModel(icon: Asset.Images.roomContextMenuReplyInThread.image,
title: VectorL10n.threadsEmptyTitle,
info: VectorL10n.threadsEmptyInfoMy,
tip: VectorL10n.threadsEmptyTip,
showAllThreadsButtonTitle: VectorL10n.threadsEmptyShowAllThreads,
showAllThreadsButtonHidden: false)
}
}
// MARK: - Private
private func viewModel(forThread thread: MXThread) -> ThreadViewModel {
private func viewModel(forThread thread: MXThread) -> ThreadModel {
let rootAvatarViewData: AvatarViewData?
let rootMessageSender: MXUser?
let lastAvatarViewData: AvatarViewData?
@ -175,15 +175,15 @@ final class ThreadListViewModel: ThreadListViewModelProtocol {
lastMessageSender = nil
}
let summaryViewModel = ThreadSummaryViewModel(numberOfReplies: thread.numberOfReplies,
lastMessageSenderAvatar: lastAvatarViewData,
lastMessageText: lastMessageText)
let summaryViewModel = ThreadSummaryModel(numberOfReplies: thread.numberOfReplies,
lastMessageSenderAvatar: lastAvatarViewData,
lastMessageText: lastMessageText)
return ThreadViewModel(rootMessageSenderAvatar: rootAvatarViewData,
rootMessageSenderDisplayName: rootMessageSender?.displayname,
rootMessageText: rootMessageText,
lastMessageTime: lastMessageTime,
summaryViewModel: summaryViewModel)
return ThreadModel(rootMessageSenderAvatar: rootAvatarViewData,
rootMessageSenderDisplayName: rootMessageSender?.displayname,
rootMessageText: rootMessageText,
lastMessageTime: lastMessageTime,
summaryViewModel: summaryViewModel)
}
private func rootMessageText(forThread thread: MXThread) -> String? {

View file

@ -38,10 +38,10 @@ protocol ThreadListViewModelProtocol {
var viewState: ThreadListViewState { get }
var titleViewModel: ThreadRoomTitleViewModel { get }
var titleViewModel: ThreadRoomTitleModel { get }
var selectedFilterType: ThreadListFilterType { get }
var numberOfThreads: Int { get }
func threadViewModel(at index: Int) -> ThreadViewModel?
func threadViewModel(at index: Int) -> ThreadModel?
}
enum ThreadListFilterType {

View file

@ -23,7 +23,7 @@ enum ThreadListViewState {
case idle
case loading
case loaded
case empty(_ viewModel: ThreadListEmptyViewModel)
case empty(_ viewModel: ThreadListEmptyModel)
case showingFilterTypes
case error(Error)
}

View file

@ -16,10 +16,10 @@
import Foundation
struct ThreadViewModel {
var rootMessageSenderAvatar: AvatarViewDataProtocol?
var rootMessageSenderDisplayName: String?
var rootMessageText: String?
var lastMessageTime: String?
var summaryViewModel: ThreadSummaryViewModel?
struct ThreadModel {
let rootMessageSenderAvatar: AvatarViewDataProtocol?
let rootMessageSenderDisplayName: String?
let rootMessageText: String?
let lastMessageTime: String?
let summaryViewModel: ThreadSummaryModel?
}

View file

@ -35,7 +35,7 @@ class ThreadTableViewCell: UITableViewCell {
separatorInset = Constants.separatorInset
}
func configure(withViewModel viewModel: ThreadViewModel) {
func configure(withViewModel viewModel: ThreadModel) {
if let rootAvatar = viewModel.rootMessageSenderAvatar {
rootMessageAvatarView.fill(with: rootAvatar)
} else {

View file

@ -16,7 +16,7 @@
import Foundation
struct ThreadListEmptyViewModel {
struct ThreadListEmptyModel {
let icon: UIImage?
let title: String?
let info: String?

View file

@ -22,6 +22,7 @@ protocol ThreadListEmptyViewDelegate: AnyObject {
func threadListEmptyViewTappedShowAllThreads(_ emptyView: ThreadListEmptyView)
}
/// View to be shown on the thread list screen when no thread is available. Use a `ThreadListEmptyModel` instance to configure.
class ThreadListEmptyView: UIView {
@IBOutlet weak var delegate: ThreadListEmptyViewDelegate?
@ -38,7 +39,7 @@ class ThreadListEmptyView: UIView {
loadNibContent()
}
func configure(withViewModel viewModel: ThreadListEmptyViewModel) {
func configure(withViewModel viewModel: ThreadListEmptyModel) {
iconView.image = viewModel.icon
titleLabel.text = viewModel.title
infoLabel.text = viewModel.info

View file

@ -54,7 +54,12 @@ final class ThreadsCoordinator: NSObject, ThreadsCoordinatorProtocol {
func start() {
let rootCoordinator = self.createThreadListCoordinator()
let rootCoordinator: Coordinator & Presentable
if let threadId = parameters.threadId {
rootCoordinator = createThreadCoordinator(forThreadId: threadId)
} else {
rootCoordinator = createThreadListCoordinator()
}
rootCoordinator.start()
@ -77,6 +82,10 @@ final class ThreadsCoordinator: NSObject, ThreadsCoordinatorProtocol {
func stop() {
if selectedThreadCoordinator != nil {
let modules = self.navigationRouter.modules
// if a thread is selected from the thread list coordinator, then navigation stack will look like:
// ... -> Screen A -> Thread List Screen -> Thread Screen
// we'll try to pop to Screen A here
// sanity check: navigation stack contains at least 3 items
guard modules.count >= 3 else {
return
}
@ -116,13 +125,13 @@ final class ThreadsCoordinator: NSObject, ThreadsCoordinatorProtocol {
return coordinator
}
private func createThreadCoordinator(forThread thread: MXThread) -> RoomCoordinator {
private func createThreadCoordinator(forThreadId threadId: String) -> RoomCoordinator {
let parameters = RoomCoordinatorParameters(navigationRouter: navigationRouter,
navigationRouterStore: nil,
session: parameters.session,
roomId: parameters.roomId,
eventId: nil,
threadId: thread.id,
threadId: threadId,
displayConfiguration: .forThreads)
let coordinator = RoomCoordinator(parameters: parameters)
coordinator.delegate = self
@ -145,7 +154,7 @@ extension ThreadsCoordinator: ThreadListCoordinatorDelegate {
}
func threadListCoordinatorDidSelectThread(_ coordinator: ThreadListCoordinatorProtocol, thread: MXThread) {
let roomCoordinator = createThreadCoordinator(forThread: thread)
let roomCoordinator = createThreadCoordinator(forThreadId: thread.id)
selectedThreadCoordinator = roomCoordinator
roomCoordinator.start()
self.add(childCoordinator: roomCoordinator)

View file

@ -45,6 +45,7 @@ final class ThreadsCoordinatorBridgePresenter: NSObject {
private let session: MXSession
private let roomId: String
private let threadId: String?
private var navigationType: NavigationType = .present
private var coordinator: ThreadsCoordinator?
@ -53,11 +54,18 @@ final class ThreadsCoordinatorBridgePresenter: NSObject {
weak var delegate: ThreadsCoordinatorBridgePresenterDelegate?
// MARK: - Setup
/// Initializer
/// - Parameters:
/// - session: Session instance
/// - roomId: Room identifier
/// - threadId: Thread identifier. Specified thread will be opened if provided, the thread list otherwise
init(session: MXSession,
roomId: String) {
roomId: String,
threadId: String?) {
self.session = session
self.roomId = roomId
self.threadId = threadId
super.init()
}
@ -71,7 +79,8 @@ final class ThreadsCoordinatorBridgePresenter: NSObject {
func present(from viewController: UIViewController, animated: Bool) {
let threadsCoordinatorParameters = ThreadsCoordinatorParameters(session: self.session,
roomId: self.roomId)
roomId: self.roomId,
threadId: self.threadId)
let threadsCoordinator = ThreadsCoordinator(parameters: threadsCoordinatorParameters)
threadsCoordinator.delegate = self
@ -89,6 +98,7 @@ final class ThreadsCoordinatorBridgePresenter: NSObject {
let threadsCoordinatorParameters = ThreadsCoordinatorParameters(session: self.session,
roomId: self.roomId,
threadId: self.threadId,
navigationRouter: navigationRouter)
let threadsCoordinator = ThreadsCoordinator(parameters: threadsCoordinatorParameters)

View file

@ -26,15 +26,20 @@ struct ThreadsCoordinatorParameters {
/// Room identifier
let roomId: String
/// Thread identifier. Specified thread will be opened if provided, the thread list otherwise
let threadId: String?
/// The navigation router that manage physical navigation
let navigationRouter: NavigationRouterType
init(session: MXSession,
roomId: String,
threadId: String?,
navigationRouter: NavigationRouterType? = nil) {
self.session = session
self.roomId = roomId
self.threadId = threadId
self.navigationRouter = navigationRouter ?? NavigationRouter(navigationController: RiotNavigationController())
}
}

View file

@ -17,7 +17,7 @@
import Foundation
/// Structure used to pass modules to routers with pop completion blocks.
struct PresentableModule {
struct NavigationModule {
/// Actual presentable of the module
let presentable: Presentable
@ -27,10 +27,10 @@ struct PresentableModule {
// MARK: - CustomStringConvertible
extension PresentableModule: CustomStringConvertible {
extension NavigationModule: CustomStringConvertible {
var description: String {
return "PresentableModule: \(presentable), pop completion: \(String(describing: popCompletion))"
return "NavigationModule: \(presentable), pop completion: \(String(describing: popCompletion))"
}
}

View file

@ -117,7 +117,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
self.didPushViewController(controller)
}
func setModules(_ modules: [PresentableModule], hideNavigationBar: Bool, animated: Bool) {
func setModules(_ modules: [NavigationModule], hideNavigationBar: Bool, animated: Bool) {
MXLog.debug("[NavigationRouter] Set modules \(modules)")
@ -221,7 +221,7 @@ final class NavigationRouter: NSObject, NavigationRouterType {
self.didPushViewController(controller)
}
func push(_ modules: [PresentableModule], animated: Bool) {
func push(_ modules: [NavigationModule], animated: Bool) {
MXLog.debug("[NavigationRouter] Push modules \(modules)")
// Avoid pushing any UINavigationController onto stack

View file

@ -45,7 +45,7 @@ protocol NavigationRouterType: AnyObject, Presentable {
/// - modules: The modules stack to set.
/// - hideNavigationBar: Specify true to hide the UINavigationBar.
/// - animated: Specify true to animate the transition.
func setModules(_ modules: [PresentableModule], hideNavigationBar: Bool, animated: Bool)
func setModules(_ modules: [NavigationModule], hideNavigationBar: Bool, animated: Bool)
/// Pop to root view controller of navigation controller and remove all others
///
@ -68,7 +68,7 @@ protocol NavigationRouterType: AnyObject, Presentable {
///
/// - Parameter modules: Modules to push
/// - Parameter animated: Specify true to animate the transition.
func push(_ modules: [PresentableModule], animated: Bool)
func push(_ modules: [NavigationModule], animated: Bool)
/// Pop last view controller from navigation controller stack
///
@ -99,7 +99,7 @@ extension NavigationRouterType {
setRootModule(module, hideNavigationBar: false, animated: false, popCompletion: popCompletion)
}
func setModules(_ modules: [PresentableModule], animated: Bool) {
func setModules(_ modules: [NavigationModule], animated: Bool) {
setModules(modules, hideNavigationBar: false, animated: animated)
}
@ -109,15 +109,15 @@ extension NavigationRouterType {
}
// MARK: - Presentable <--> ModulePresentable Transitive Methods
// MARK: - Presentable <--> NavigationModule Transitive Methods
extension NavigationRouterType {
func setRootModule(_ module: PresentableModule) {
func setRootModule(_ module: NavigationModule) {
setRootModule(module.presentable, popCompletion: module.popCompletion)
}
func push(_ module: PresentableModule, animated: Bool) {
func push(_ module: NavigationModule, animated: Bool) {
push(module.presentable, animated: animated, popCompletion: module.popCompletion)
}

View file

@ -31,8 +31,8 @@ extension Presentable {
/// Returns a new module from the presentable without a pop completion block
/// - Returns: Module
func toModule() -> PresentableModule {
return PresentableModule(presentable: self, popCompletion: nil)
func toModule() -> NavigationModule {
return NavigationModule(presentable: self, popCompletion: nil)
}
}