From 55c3749486ffe510fce576264b969335f1e67874 Mon Sep 17 00:00:00 2001 From: Andy Uhnak Date: Tue, 29 Mar 2022 16:45:37 +0100 Subject: [PATCH] New loading indicators when creating a room --- Riot/Assets/en.lproj/Vector.strings | 1 + Riot/Generated/Strings.swift | 4 ++ .../UserIndicatorPresenterWrapper.swift | 56 ------------------- .../Common/Recents/RecentsViewController.h | 7 ++- .../Common/Recents/RecentsViewController.m | 32 +++++++---- .../UserIndicators/UserIndicatorStore.swift | 12 +++- .../EnterNewRoomDetailsViewController.swift | 11 ++-- .../EnterNewRoomDetailsViewModel.swift | 3 + Riot/Modules/TabBar/TabBarCoordinator.swift | 8 +-- changelog.d/5606.change | 1 + 10 files changed, 55 insertions(+), 80 deletions(-) delete mode 100644 Riot/Modules/Common/ActivityIndicator/UserIndicatorPresenterWrapper.swift create mode 100644 changelog.d/5606.change diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index af014ed7df..ebef95ea4e 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -1767,6 +1767,7 @@ Tap the + to start adding people."; "create_room_placeholder_address" = "#testroom:matrix.org"; "create_room_suggest_room" = "Suggest to space members"; "create_room_suggest_room_footer" = "Suggested rooms are promoted to space members as good to join."; +"create_room_processing" = "Creating room"; // MARK: - Room Info diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index b8a988c0f1..db1521d915 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -935,6 +935,10 @@ public class VectorL10n: NSObject { public static var createRoomPlaceholderTopic: String { return VectorL10n.tr("Vector", "create_room_placeholder_topic") } + /// Creating room + public static var createRoomProcessing: String { + return VectorL10n.tr("Vector", "create_room_processing") + } /// PROMOTION public static var createRoomPromotionHeader: String { return VectorL10n.tr("Vector", "create_room_promotion_header") diff --git a/Riot/Modules/Common/ActivityIndicator/UserIndicatorPresenterWrapper.swift b/Riot/Modules/Common/ActivityIndicator/UserIndicatorPresenterWrapper.swift deleted file mode 100644 index 7d1bd9d3b3..0000000000 --- a/Riot/Modules/Common/ActivityIndicator/UserIndicatorPresenterWrapper.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// Copyright 2021 New Vector 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 Foundation -import CommonKit - -/// A convenience objc-compatible wrapper around `UserIndicatorTypePresenterProtocol`. -/// -/// This class wraps swift-only protocol by exposing multiple methods instead of accepting struct types -/// and it keeps a track of `UserIndicator`s instead of returning them to the caller. -@objc final class UserIndicatorPresenterWrapper: NSObject { - private let presenter: UserIndicatorTypePresenterProtocol - private var loadingIndicator: UserIndicator? - private var otherIndicators = [UserIndicator]() - - init(presenter: UserIndicatorTypePresenterProtocol) { - self.presenter = presenter - } - - @objc func presentLoadingIndicator() { - presentLoadingIndicator(label: VectorL10n.homeSyncing) - } - - @objc func presentLoadingIndicator(label: String) { - guard loadingIndicator == nil else { - // The app is very liberal with calling `presentLoadingIndicator` (often not matched by corresponding `dismissLoadingIndicator`), - // so there is no reason to keep adding new indiciators if there is one already showing. - return - } - - MXLog.debug("[UserIndicatorPresenterWrapper] Present loading indicator") - loadingIndicator = presenter.present(.loading(label: label, isInteractionBlocking: false)) - } - - @objc func dismissLoadingIndicator() { - MXLog.debug("[UserIndicatorPresenterWrapper] Dismiss loading indicator") - loadingIndicator = nil - } - - @objc func presentSuccess(label: String) { - presenter.present(.success(label: label)).store(in: &otherIndicators) - } -} diff --git a/Riot/Modules/Common/Recents/RecentsViewController.h b/Riot/Modules/Common/Recents/RecentsViewController.h index 6867e063d8..a2fefb47d3 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.h +++ b/Riot/Modules/Common/Recents/RecentsViewController.h @@ -19,7 +19,7 @@ @class RootTabEmptyView; @class AnalyticsScreenTracker; -@class UserIndicatorPresenterWrapper; +@class UserIndicatorStore; /** Notification to be posted when recents data is ready. Notification object will be the RecentsViewController instance. @@ -98,9 +98,10 @@ FOUNDATION_EXPORT NSString *const RecentsViewControllerDataReadyNotification; @property (nonatomic) AnalyticsScreenTracker *screenTracker; /** - Presenter for displaying app-wide user indicators. If not set, the view controller will use legacy activity indicators + A store of user indicators that lets the room present and dismiss indicators without + worrying about the presentation context or memory management. */ -@property (nonatomic, strong) UserIndicatorPresenterWrapper *indicatorPresenter; +@property (nonatomic, strong) UserIndicatorStore *userIndicatorStore; /** Return the sticky header for the specified section of the table view diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index a6a59f00cd..ea12f0516a 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -69,6 +69,9 @@ @interface RecentsViewController () UserIndicatorCancel { @@ -51,4 +51,12 @@ import CommonKit ) ) } + + /// Present a success message that will be automatically dismissed after a few seconds. + /// + /// Note: This is a convenience function callable by objective-c code + @objc func presentSuccess(label: String) { + let indicator = presenter.present(.success(label: label)) + indicators.append(indicator) + } } diff --git a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift index 0ea21a4b31..233fab0a44 100644 --- a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift +++ b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewController.swift @@ -17,6 +17,7 @@ */ import UIKit +import CommonKit final class EnterNewRoomDetailsViewController: UIViewController { @@ -47,7 +48,9 @@ final class EnterNewRoomDetailsViewController: UIViewController { private var theme: Theme! private var keyboardAvoider: KeyboardAvoider? private var errorPresenter: MXKErrorPresentation! - private var activityPresenter: ActivityIndicatorPresenter! + private var userIndicatorPresenter: UserIndicatorTypePresenterProtocol! + private var loadingIndicator: UserIndicator? + private lazy var createBarButtonItem: MXKBarButtonItem = { let title: String switch viewModel.actionType { @@ -262,7 +265,7 @@ final class EnterNewRoomDetailsViewController: UIViewController { self.setupViews() self.keyboardAvoider = KeyboardAvoider(scrollViewContainerView: self.view, scrollView: self.mainTableView) - self.activityPresenter = ActivityIndicatorPresenter() + self.userIndicatorPresenter = UserIndicatorTypePresenter(presentingViewController: self) self.errorPresenter = MXKErrorAlertPresentation() self.registerThemeServiceDidChangeThemeNotification() @@ -352,11 +355,11 @@ final class EnterNewRoomDetailsViewController: UIViewController { } private func renderLoading() { - self.activityPresenter.presentActivityIndicator(on: self.view, animated: true) + loadingIndicator = userIndicatorPresenter.present(.loading(label: VectorL10n.createRoomProcessing, isInteractionBlocking: true)) } private func render(error: Error) { - self.activityPresenter.removeCurrentActivityIndicator(animated: true) + loadingIndicator = nil self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil) } diff --git a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift index 3a518e846c..a5bd82945e 100644 --- a/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift +++ b/Riot/Modules/CreateRoom/EnterNewRoomDetails/EnterNewRoomDetailsViewModel.swift @@ -115,6 +115,7 @@ final class EnterNewRoomDetailsViewModel: EnterNewRoomDetailsViewModelType { fatalError("[EnterNewRoomDetailsViewModel] createRoom: room name cannot be nil.") } + viewState = .loading currentOperation = session.createRoom( withName: roomName, joinRule: roomCreationParameters.joinRule, @@ -125,6 +126,8 @@ final class EnterNewRoomDetailsViewModel: EnterNewRoomDetailsViewModelType { completion: { response in switch response { case .success(let room): + self.viewState = .loaded + if let parentSpace = self.parentSpace { self.add(room, to: parentSpace) } else { diff --git a/Riot/Modules/TabBar/TabBarCoordinator.swift b/Riot/Modules/TabBar/TabBarCoordinator.swift index 4a5b5c1650..cd398cd59a 100644 --- a/Riot/Modules/TabBar/TabBarCoordinator.swift +++ b/Riot/Modules/TabBar/TabBarCoordinator.swift @@ -239,7 +239,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { homeViewController.tabBarItem.tag = Int(TABBAR_HOME_INDEX) homeViewController.tabBarItem.image = homeViewController.tabBarItem.image homeViewController.accessibilityLabel = VectorL10n.titleHome - homeViewController.indicatorPresenter = UserIndicatorPresenterWrapper(presenter: indicatorPresenter) + homeViewController.userIndicatorStore = UserIndicatorStore(presenter: indicatorPresenter) let wrapperViewController = HomeViewControllerWithBannerWrapperViewController(viewController: homeViewController) return wrapperViewController @@ -249,7 +249,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { let favouritesViewController: FavouritesViewController = FavouritesViewController.instantiate() favouritesViewController.tabBarItem.tag = Int(TABBAR_FAVOURITES_INDEX) favouritesViewController.accessibilityLabel = VectorL10n.titleFavourites - favouritesViewController.indicatorPresenter = UserIndicatorPresenterWrapper(presenter: indicatorPresenter) + favouritesViewController.userIndicatorStore = UserIndicatorStore(presenter: indicatorPresenter) return favouritesViewController } @@ -257,7 +257,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { let peopleViewController: PeopleViewController = PeopleViewController.instantiate() peopleViewController.tabBarItem.tag = Int(TABBAR_PEOPLE_INDEX) peopleViewController.accessibilityLabel = VectorL10n.titlePeople - peopleViewController.indicatorPresenter = UserIndicatorPresenterWrapper(presenter: indicatorPresenter) + peopleViewController.userIndicatorStore = UserIndicatorStore(presenter: indicatorPresenter) return peopleViewController } @@ -265,7 +265,7 @@ final class TabBarCoordinator: NSObject, TabBarCoordinatorType { let roomsViewController: RoomsViewController = RoomsViewController.instantiate() roomsViewController.tabBarItem.tag = Int(TABBAR_ROOMS_INDEX) roomsViewController.accessibilityLabel = VectorL10n.titleRooms - roomsViewController.indicatorPresenter = UserIndicatorPresenterWrapper(presenter: indicatorPresenter) + roomsViewController.userIndicatorStore = UserIndicatorStore(presenter: indicatorPresenter) return roomsViewController } diff --git a/changelog.d/5606.change b/changelog.d/5606.change new file mode 100644 index 0000000000..15c4fcd842 --- /dev/null +++ b/changelog.d/5606.change @@ -0,0 +1 @@ +Room: New loading indicators when creating a room