mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Fixes #2320 - Implement support for (un)marking rooms as favourite from the room list and room detail screens
This commit is contained in:
@@ -49,6 +49,7 @@ final class AppSettings {
|
||||
case mentionsBadgeEnabled
|
||||
case roomListFiltersEnabled
|
||||
case markAsUnreadEnabled
|
||||
case markAsFavouriteEnabled
|
||||
}
|
||||
|
||||
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
|
||||
@@ -285,6 +286,9 @@ final class AppSettings {
|
||||
@UserPreference(key: UserDefaultsKeys.markAsUnreadEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||
var markAsUnreadEnabled
|
||||
|
||||
@UserPreference(key: UserDefaultsKeys.markAsFavouriteEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||
var markAsFavouriteEnabled
|
||||
|
||||
#endif
|
||||
|
||||
// MARK: - Shared
|
||||
|
||||
@@ -410,7 +410,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
|
||||
Task {
|
||||
// Flag the room as read on entering, the timeline will take care of the read receipts
|
||||
await roomProxy.flagAsRead()
|
||||
await roomProxy.flagAsUnread(false)
|
||||
}
|
||||
|
||||
let userID = userSession.clientProxy.userID
|
||||
@@ -523,6 +523,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
let params = RoomDetailsScreenCoordinatorParameters(accountUserID: userSession.userID,
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: userSession.mediaProvider,
|
||||
analyticsService: analytics,
|
||||
userIndicatorController: userIndicatorController,
|
||||
notificationSettings: userSession.clientProxy.notificationSettings,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: appSettings.permalinkBaseURL,
|
||||
|
||||
@@ -1851,6 +1851,23 @@ class RoomProxyMock: RoomProxyProtocol {
|
||||
set(value) { underlyingIsEncrypted = value }
|
||||
}
|
||||
var underlyingIsEncrypted: Bool!
|
||||
var isFavouriteCallsCount = 0
|
||||
var isFavouriteCalled: Bool {
|
||||
return isFavouriteCallsCount > 0
|
||||
}
|
||||
|
||||
var isFavourite: Bool {
|
||||
get async {
|
||||
isFavouriteCallsCount += 1
|
||||
if let isFavouriteClosure = isFavouriteClosure {
|
||||
return await isFavouriteClosure()
|
||||
} else {
|
||||
return underlyingIsFavourite
|
||||
}
|
||||
}
|
||||
}
|
||||
var underlyingIsFavourite: Bool!
|
||||
var isFavouriteClosure: (() async -> Bool)?
|
||||
var membership: Membership {
|
||||
get { return underlyingMembership }
|
||||
set(value) { underlyingMembership = value }
|
||||
@@ -2237,40 +2254,6 @@ class RoomProxyMock: RoomProxyProtocol {
|
||||
return canUserTriggerRoomNotificationUserIDReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - flagAsUnread
|
||||
|
||||
var flagAsUnreadCallsCount = 0
|
||||
var flagAsUnreadCalled: Bool {
|
||||
return flagAsUnreadCallsCount > 0
|
||||
}
|
||||
var flagAsUnreadReturnValue: Result<Void, RoomProxyError>!
|
||||
var flagAsUnreadClosure: (() async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func flagAsUnread() async -> Result<Void, RoomProxyError> {
|
||||
flagAsUnreadCallsCount += 1
|
||||
if let flagAsUnreadClosure = flagAsUnreadClosure {
|
||||
return await flagAsUnreadClosure()
|
||||
} else {
|
||||
return flagAsUnreadReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - flagAsRead
|
||||
|
||||
var flagAsReadCallsCount = 0
|
||||
var flagAsReadCalled: Bool {
|
||||
return flagAsReadCallsCount > 0
|
||||
}
|
||||
var flagAsReadReturnValue: Result<Void, RoomProxyError>!
|
||||
var flagAsReadClosure: (() async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func flagAsRead() async -> Result<Void, RoomProxyError> {
|
||||
flagAsReadCallsCount += 1
|
||||
if let flagAsReadClosure = flagAsReadClosure {
|
||||
return await flagAsReadClosure()
|
||||
} else {
|
||||
return flagAsReadReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - markAsRead
|
||||
|
||||
var markAsReadReceiptTypeCallsCount = 0
|
||||
@@ -2314,6 +2297,48 @@ class RoomProxyMock: RoomProxyProtocol {
|
||||
return sendTypingNotificationIsTypingReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - flagAsUnread
|
||||
|
||||
var flagAsUnreadCallsCount = 0
|
||||
var flagAsUnreadCalled: Bool {
|
||||
return flagAsUnreadCallsCount > 0
|
||||
}
|
||||
var flagAsUnreadReceivedIsUnread: Bool?
|
||||
var flagAsUnreadReceivedInvocations: [Bool] = []
|
||||
var flagAsUnreadReturnValue: Result<Void, RoomProxyError>!
|
||||
var flagAsUnreadClosure: ((Bool) async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError> {
|
||||
flagAsUnreadCallsCount += 1
|
||||
flagAsUnreadReceivedIsUnread = isUnread
|
||||
flagAsUnreadReceivedInvocations.append(isUnread)
|
||||
if let flagAsUnreadClosure = flagAsUnreadClosure {
|
||||
return await flagAsUnreadClosure(isUnread)
|
||||
} else {
|
||||
return flagAsUnreadReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - flagAsFavourite
|
||||
|
||||
var flagAsFavouriteCallsCount = 0
|
||||
var flagAsFavouriteCalled: Bool {
|
||||
return flagAsFavouriteCallsCount > 0
|
||||
}
|
||||
var flagAsFavouriteReceivedIsFavourite: Bool?
|
||||
var flagAsFavouriteReceivedInvocations: [Bool] = []
|
||||
var flagAsFavouriteReturnValue: Result<Void, RoomProxyError>!
|
||||
var flagAsFavouriteClosure: ((Bool) async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func flagAsFavourite(_ isFavourite: Bool) async -> Result<Void, RoomProxyError> {
|
||||
flagAsFavouriteCallsCount += 1
|
||||
flagAsFavouriteReceivedIsFavourite = isFavourite
|
||||
flagAsFavouriteReceivedInvocations.append(isFavourite)
|
||||
if let flagAsFavouriteClosure = flagAsFavouriteClosure {
|
||||
return await flagAsFavouriteClosure(isFavourite)
|
||||
} else {
|
||||
return flagAsFavouriteReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - canUserJoinCall
|
||||
|
||||
var canUserJoinCallUserIDCallsCount = 0
|
||||
|
||||
@@ -81,9 +81,10 @@ extension RoomProxyMock {
|
||||
canUserTriggerRoomNotificationUserIDReturnValue = .success(configuration.canUserTriggerRoomNotification)
|
||||
canUserJoinCallUserIDReturnValue = .success(configuration.canUserJoinCall)
|
||||
|
||||
flagAsReadReturnValue = .success(())
|
||||
flagAsUnreadReturnValue = .success(())
|
||||
markAsReadReceiptTypeReturnValue = .success(())
|
||||
underlyingIsFavourite = false
|
||||
flagAsFavouriteReturnValue = .success(())
|
||||
|
||||
let widgetDriver = ElementCallWidgetDriverMock()
|
||||
widgetDriver.underlyingMessagePublisher = .init()
|
||||
|
||||
@@ -172,7 +172,8 @@ enum A11yIdentifiers {
|
||||
let people = "room_details-people"
|
||||
let invite = "room_details-invite"
|
||||
let notifications = "room_details-notifications"
|
||||
let pollsHistory = "romm_details-polls_history"
|
||||
let pollsHistory = "room_details-polls_history"
|
||||
let favourite = "room_details-favourite"
|
||||
}
|
||||
|
||||
struct RoomMemberDetailsScreen {
|
||||
|
||||
@@ -79,8 +79,9 @@ struct ShimmerOverlay_Previews: PreviewProvider, TestablePreview {
|
||||
static let viewModel = HomeScreenViewModel(userSession: MockUserSession(clientProxy: MockClientProxy(userID: ""),
|
||||
mediaProvider: MockMediaProvider(),
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock()),
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
@@ -53,8 +53,9 @@ final class HomeScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
init(parameters: HomeScreenCoordinatorParameters) {
|
||||
viewModel = HomeScreenViewModel(userSession: parameters.userSession,
|
||||
selectedRoomPublisher: parameters.selectedRoomPublisher,
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
selectedRoomPublisher: parameters.selectedRoomPublisher,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
bugReportService = parameters.bugReportService
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ enum HomeScreenViewAction {
|
||||
case globalSearch
|
||||
case markRoomAsUnread(roomIdentifier: String)
|
||||
case markRoomAsRead(roomIdentifier: String)
|
||||
case markRoomAsFavourite(roomIdentifier: String, isFavourite: Bool)
|
||||
}
|
||||
|
||||
enum HomeScreenRoomListMode: CustomStringConvertible {
|
||||
@@ -95,6 +96,7 @@ struct HomeScreenViewState: BindableState {
|
||||
|
||||
var shouldShowFilters = false
|
||||
var markAsUnreadEnabled = false
|
||||
var markAsFavouriteEnabled = false
|
||||
|
||||
var hasPendingInvitations = false
|
||||
var hasUnreadPendingInvitations = false
|
||||
@@ -154,6 +156,8 @@ struct HomeScreenRoom: Identifiable, Equatable {
|
||||
|
||||
let isHighlighted: Bool
|
||||
|
||||
let isFavourite: Bool
|
||||
|
||||
var timestamp: String?
|
||||
|
||||
var lastMessage: AttributedString?
|
||||
@@ -168,6 +172,7 @@ struct HomeScreenRoom: Identifiable, Equatable {
|
||||
name: "Placeholder room name",
|
||||
badges: .init(isDotShown: false, isMentionShown: false, isMuteShown: false, isCallShown: false),
|
||||
isHighlighted: false,
|
||||
isFavourite: false,
|
||||
timestamp: "Now",
|
||||
lastMessage: placeholderLastMessage,
|
||||
isPlaceholder: true)
|
||||
@@ -194,6 +199,7 @@ extension HomeScreenRoom {
|
||||
isMuteShown: isMuteShown,
|
||||
isCallShown: isCallShown),
|
||||
isHighlighted: isHighlighted,
|
||||
isFavourite: details.isFavourite,
|
||||
timestamp: details.lastMessageFormattedTimestamp,
|
||||
lastMessage: details.lastMessage,
|
||||
avatarURL: details.avatarURL)
|
||||
|
||||
@@ -21,6 +21,7 @@ typealias HomeScreenViewModelType = StateStoreViewModel<HomeScreenViewState, Hom
|
||||
|
||||
class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol {
|
||||
private let userSession: UserSessionProtocol
|
||||
private let analyticsService: AnalyticsService
|
||||
private let appSettings: AppSettings
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
|
||||
@@ -38,10 +39,12 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
}
|
||||
|
||||
init(userSession: UserSessionProtocol,
|
||||
selectedRoomPublisher: CurrentValuePublisher<String?, Never>,
|
||||
analyticsService: AnalyticsService,
|
||||
appSettings: AppSettings,
|
||||
selectedRoomPublisher: CurrentValuePublisher<String?, Never>,
|
||||
userIndicatorController: UserIndicatorControllerProtocol) {
|
||||
self.userSession = userSession
|
||||
self.analyticsService = analyticsService
|
||||
self.appSettings = appSettings
|
||||
self.userIndicatorController = userIndicatorController
|
||||
|
||||
@@ -115,6 +118,10 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
.weakAssign(to: \.state.markAsUnreadEnabled, on: self)
|
||||
.store(in: &cancellables)
|
||||
|
||||
appSettings.$markAsFavouriteEnabled
|
||||
.weakAssign(to: \.state.markAsFavouriteEnabled, on: self)
|
||||
.store(in: &cancellables)
|
||||
|
||||
appSettings.$hideUnreadMessagesBadge
|
||||
.sink { [weak self] _ in self?.updateRooms() }
|
||||
.store(in: &cancellables)
|
||||
@@ -182,9 +189,9 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
return
|
||||
}
|
||||
|
||||
switch await roomProxy.flagAsUnread() {
|
||||
switch await roomProxy.flagAsUnread(true) {
|
||||
case .success:
|
||||
ServiceLocator.shared.analytics.trackInteraction(name: .MobileRoomListRoomContextMenuUnreadToggle)
|
||||
analyticsService.trackInteraction(name: .MobileRoomListRoomContextMenuUnreadToggle)
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed marking room \(roomIdentifier) as unread with error: \(error)")
|
||||
}
|
||||
@@ -196,9 +203,9 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
return
|
||||
}
|
||||
|
||||
switch await roomProxy.flagAsRead() {
|
||||
switch await roomProxy.flagAsUnread(false) {
|
||||
case .success:
|
||||
ServiceLocator.shared.analytics.trackInteraction(name: .MobileRoomListRoomContextMenuUnreadToggle)
|
||||
analyticsService.trackInteraction(name: .MobileRoomListRoomContextMenuUnreadToggle)
|
||||
|
||||
if case .failure(let error) = await roomProxy.markAsRead(receiptType: appSettings.sharePresence ? .read : .readPrivate) {
|
||||
MXLog.error("Failed marking room \(roomIdentifier) as read with error: \(error)")
|
||||
@@ -207,6 +214,10 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
MXLog.error("Failed flagging room \(roomIdentifier) as read with error: \(error)")
|
||||
}
|
||||
}
|
||||
case .markRoomAsFavourite(let roomIdentifier, let isFavourite):
|
||||
Task {
|
||||
await markRoomAsFavourite(roomIdentifier, isFavourite: isFavourite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,7 +252,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
return
|
||||
}
|
||||
|
||||
ServiceLocator.shared.analytics.signpost.beginFirstRooms()
|
||||
analyticsService.signpost.beginFirstRooms()
|
||||
|
||||
let hasUserBeenMigrated = appSettings.migratedAccounts[userSession.userID] == true
|
||||
|
||||
@@ -322,7 +333,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
}
|
||||
|
||||
if roomListMode == .rooms, state.roomListMode == .skeletons {
|
||||
ServiceLocator.shared.analytics.signpost.endFirstRooms()
|
||||
analyticsService.signpost.endFirstRooms()
|
||||
}
|
||||
|
||||
state.roomListMode = roomListMode
|
||||
@@ -399,6 +410,20 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
roomSummaryProvider.updateVisibleRange(range)
|
||||
}
|
||||
|
||||
private func markRoomAsFavourite(_ roomID: String, isFavourite: Bool) async {
|
||||
guard let roomProxy = await userSession.clientProxy.roomForIdentifier(roomID) else {
|
||||
MXLog.error("Failed retrieving room for identifier: \(roomID)")
|
||||
return
|
||||
}
|
||||
|
||||
switch await roomProxy.flagAsFavourite(isFavourite) {
|
||||
case .success:
|
||||
analyticsService.trackInteraction(name: .MobileRoomListRoomContextMenuFavouriteToggle)
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed marking room \(roomID) as favourite: \(isFavourite) with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private static let leaveRoomLoadingID = "LeaveRoomLoading"
|
||||
|
||||
private func startLeaveRoomProcess(roomId: String) {
|
||||
|
||||
@@ -238,8 +238,9 @@ struct HomeScreen_Previews: PreviewProvider, TestablePreview {
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
appSettings: appSettings,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,8 +155,9 @@ struct HomeScreenEmptyStateView_Previews: PreviewProvider, TestablePreview {
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}()
|
||||
}
|
||||
|
||||
+2
-1
@@ -73,8 +73,9 @@ struct HomeScreenRecoveryKeyConfirmationBanner_Previews: PreviewProvider, Testab
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,8 +181,9 @@ struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}()
|
||||
|
||||
@@ -193,8 +194,9 @@ struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}()
|
||||
|
||||
|
||||
@@ -63,6 +63,22 @@ struct HomeScreenRoomList: View {
|
||||
}
|
||||
}
|
||||
|
||||
if context.viewState.markAsFavouriteEnabled {
|
||||
if room.isFavourite {
|
||||
Button {
|
||||
context.send(viewAction: .markRoomAsFavourite(roomIdentifier: room.id, isFavourite: false))
|
||||
} label: {
|
||||
Label(L10n.commonFavourited, icon: \.favouriteSolid)
|
||||
}
|
||||
} else {
|
||||
Button {
|
||||
context.send(viewAction: .markRoomAsFavourite(roomIdentifier: room.id, isFavourite: true))
|
||||
} label: {
|
||||
Label(L10n.commonFavourite, icon: \.favourite)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
context.send(viewAction: .showRoomDetails(roomIdentifier: room.id))
|
||||
} label: {
|
||||
|
||||
@@ -73,8 +73,9 @@ struct HomeScreenSessionVerificationBanner_Previews: PreviewProvider, TestablePr
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,14 +186,15 @@ private extension InvitesScreenRoomDetails {
|
||||
avatarURL: nil,
|
||||
lastMessage: nil,
|
||||
lastMessageFormattedTimestamp: nil,
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 0,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 0,
|
||||
notificationMode: nil,
|
||||
canonicalAlias: "#footest:somewhere.org",
|
||||
inviter: inviter,
|
||||
hasOngoingCall: false)
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)
|
||||
return .init(roomDetails: dmRoom, isUnread: false)
|
||||
}
|
||||
|
||||
@@ -209,14 +210,15 @@ private extension InvitesScreenRoomDetails {
|
||||
avatarURL: avatarURL,
|
||||
lastMessage: nil,
|
||||
lastMessageFormattedTimestamp: nil,
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 0,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 0,
|
||||
notificationMode: nil,
|
||||
canonicalAlias: alias,
|
||||
inviter: inviter,
|
||||
hasOngoingCall: false)
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)
|
||||
return .init(roomDetails: dmRoom, isUnread: isUnread)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ struct RoomDetailsScreenCoordinatorParameters {
|
||||
let accountUserID: String
|
||||
let roomProxy: RoomProxyProtocol
|
||||
let mediaProvider: MediaProviderProtocol
|
||||
let analyticsService: AnalyticsService
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
let notificationSettings: NotificationSettingsProxyProtocol
|
||||
let attributedStringBuilder: AttributedStringBuilderProtocol
|
||||
@@ -49,6 +50,7 @@ final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
|
||||
viewModel = RoomDetailsScreenViewModel(accountUserID: parameters.accountUserID,
|
||||
roomProxy: parameters.roomProxy,
|
||||
mediaProvider: parameters.mediaProvider,
|
||||
analyticsService: parameters.analyticsService,
|
||||
userIndicatorController: parameters.userIndicatorController,
|
||||
notificationSettingsProxy: parameters.notificationSettings,
|
||||
attributedStringBuilder: parameters.attributedStringBuilder)
|
||||
|
||||
@@ -129,6 +129,8 @@ struct RoomDetailsScreenViewStateBindings {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var isFavourite = false
|
||||
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<RoomDetailsScreenErrorType>?
|
||||
@@ -180,6 +182,7 @@ enum RoomDetailsScreenViewAction {
|
||||
case processToogleMuteNotifications
|
||||
case displayAvatar
|
||||
case processTapPolls
|
||||
case toggleFavourite(isFavourite: Bool)
|
||||
}
|
||||
|
||||
enum RoomDetailsScreenViewShortcut {
|
||||
|
||||
@@ -22,6 +22,7 @@ typealias RoomDetailsScreenViewModelType = StateStoreViewModel<RoomDetailsScreen
|
||||
class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScreenViewModelProtocol {
|
||||
private let accountUserID: String
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
private let analyticsService: AnalyticsService
|
||||
private let mediaProvider: MediaProviderProtocol
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private let notificationSettingsProxy: NotificationSettingsProxyProtocol
|
||||
@@ -42,12 +43,14 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
init(accountUserID: String,
|
||||
roomProxy: RoomProxyProtocol,
|
||||
mediaProvider: MediaProviderProtocol,
|
||||
analyticsService: AnalyticsService,
|
||||
userIndicatorController: UserIndicatorControllerProtocol,
|
||||
notificationSettingsProxy: NotificationSettingsProxyProtocol,
|
||||
attributedStringBuilder: AttributedStringBuilderProtocol) {
|
||||
self.accountUserID = accountUserID
|
||||
self.roomProxy = roomProxy
|
||||
self.mediaProvider = mediaProvider
|
||||
self.analyticsService = analyticsService
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.notificationSettingsProxy = notificationSettingsProxy
|
||||
self.attributedStringBuilder = attributedStringBuilder
|
||||
@@ -67,6 +70,8 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
notificationSettingsState: .loading,
|
||||
bindings: .init()),
|
||||
imageProvider: mediaProvider)
|
||||
|
||||
updateRoomInfo()
|
||||
|
||||
setupRoomSubscription()
|
||||
fetchMembers()
|
||||
@@ -122,6 +127,8 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
displayFullScreenAvatar()
|
||||
case .processTapPolls:
|
||||
actionsSubject.send(.requestPollsHistoryPresentation)
|
||||
case .toggleFavourite(let isFavourite):
|
||||
Task { await toggleFavourite(isFavourite) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,21 +136,28 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
|
||||
private func setupRoomSubscription() {
|
||||
roomProxy.actions
|
||||
.filter { $0 == .stateUpdate }
|
||||
.filter { $0 == .roomInfoUpdate }
|
||||
.throttle(for: .milliseconds(200), scheduler: DispatchQueue.main, latest: true)
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
self.state.title = self.roomProxy.roomTitle
|
||||
|
||||
let topic = attributedStringBuilder.fromPlain(self.roomProxy.topic)
|
||||
self.state.topic = topic
|
||||
self.state.topicSummary = topic?.unattributedStringByReplacingNewlinesWithSpaces()
|
||||
self.state.avatarURL = self.roomProxy.avatarURL
|
||||
self.state.joinedMembersCount = self.roomProxy.joinedMembersCount
|
||||
self?.updateRoomInfo()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
private func updateRoomInfo() {
|
||||
state.title = roomProxy.roomTitle
|
||||
|
||||
let topic = attributedStringBuilder.fromPlain(roomProxy.topic)
|
||||
state.topic = topic
|
||||
state.topicSummary = topic?.unattributedStringByReplacingNewlinesWithSpaces()
|
||||
state.avatarURL = roomProxy.avatarURL
|
||||
state.joinedMembersCount = roomProxy.joinedMembersCount
|
||||
|
||||
Task {
|
||||
state.bindings.isFavourite = await roomProxy.isFavourite
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchMembers() {
|
||||
Task {
|
||||
await fetchMembersIfNeeded()
|
||||
@@ -245,6 +259,15 @@ class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScr
|
||||
}
|
||||
state.isProcessingMuteToggleAction = false
|
||||
}
|
||||
|
||||
private func toggleFavourite(_ isFavourite: Bool) async {
|
||||
if case let .failure(error) = await roomProxy.flagAsFavourite(isFavourite) {
|
||||
MXLog.error("Failed flagging room as favourite with error: \(error)")
|
||||
state.bindings.isFavourite = !isFavourite
|
||||
} else {
|
||||
analyticsService.trackInteraction(name: .MobileRoomFavouriteToggle)
|
||||
}
|
||||
}
|
||||
|
||||
private static let leaveRoomLoadingID = "LeaveRoomLoading"
|
||||
|
||||
|
||||
@@ -187,6 +187,13 @@ struct RoomDetailsScreen: View {
|
||||
})
|
||||
.disabled(context.viewState.notificationSettingsState.isLoading)
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomDetailsScreen.notifications)
|
||||
|
||||
ListRow(label: .default(title: L10n.commonFavourite, icon: \.favourite),
|
||||
kind: .toggle($context.isFavourite))
|
||||
.accessibilityIdentifier(A11yIdentifiers.roomDetailsScreen.favourite)
|
||||
.onChange(of: context.isFavourite) { newValue in
|
||||
context.send(viewAction: .toggleFavourite(isFavourite: newValue))
|
||||
}
|
||||
}
|
||||
.disabled(context.viewState.notificationSettingsState.isLoading)
|
||||
}
|
||||
@@ -306,6 +313,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
return RoomDetailsScreenViewModel(accountUserID: RoomMemberProxyMock.mockMe.userID,
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettingsProxy: notificationSettingsProxy,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .userDirectory,
|
||||
@@ -331,6 +339,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
return RoomDetailsScreenViewModel(accountUserID: RoomMemberProxyMock.mockMe.userID,
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettingsProxy: notificationSettingsProxy,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .userDirectory,
|
||||
@@ -355,6 +364,7 @@ struct RoomDetailsScreen_Previews: PreviewProvider, TestablePreview {
|
||||
return RoomDetailsScreenViewModel(accountUserID: RoomMemberProxyMock.mockMe.userID,
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettingsProxy: notificationSettingsProxy,
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: .userDirectory,
|
||||
|
||||
@@ -293,7 +293,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
|
||||
roomProxy
|
||||
.actions
|
||||
.filter { $0 == .stateUpdate }
|
||||
.filter { $0 == .roomInfoUpdate }
|
||||
.throttle(for: .seconds(1), scheduler: DispatchQueue.main, latest: true)
|
||||
.sink { [weak self] _ in
|
||||
guard let self else { return }
|
||||
|
||||
+3
-1
@@ -50,9 +50,11 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
||||
var userSuggestionsEnabled: Bool { get set }
|
||||
var mentionsBadgeEnabled: Bool { get set }
|
||||
var roomListFiltersEnabled: Bool { get set }
|
||||
var markAsUnreadEnabled: Bool { get set }
|
||||
var hideUnreadMessagesBadge: Bool { get set }
|
||||
|
||||
var markAsUnreadEnabled: Bool { get set }
|
||||
var markAsFavouriteEnabled: Bool { get set }
|
||||
|
||||
var elementCallBaseURL: URL { get set }
|
||||
}
|
||||
|
||||
|
||||
+4
@@ -60,6 +60,10 @@ struct DeveloperOptionsScreen: View {
|
||||
Text("Mark as unread")
|
||||
}
|
||||
|
||||
Toggle(isOn: $context.markAsFavouriteEnabled) {
|
||||
Text("Mark as favourite")
|
||||
}
|
||||
|
||||
Toggle(isOn: $context.hideUnreadMessagesBadge) {
|
||||
Text("Hide grey dots")
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ class RoomProxy: RoomProxyProtocol {
|
||||
|
||||
await timeline.subscribeForUpdates()
|
||||
|
||||
subscribeToRoomStateUpdates()
|
||||
subscribeToRoomInfoUpdates()
|
||||
|
||||
subscribeToTypingNotifications()
|
||||
}
|
||||
@@ -133,6 +133,12 @@ class RoomProxy: RoomProxyProtocol {
|
||||
(try? room.isEncrypted()) ?? false
|
||||
}
|
||||
|
||||
var isFavourite: Bool {
|
||||
get async {
|
||||
await (try? room.roomInfo().isFavourite) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
var hasOngoingCall: Bool {
|
||||
room.hasActiveRoomCall()
|
||||
}
|
||||
@@ -367,31 +373,7 @@ class RoomProxy: RoomProxyProtocol {
|
||||
return .failure(.failedCheckingPermission)
|
||||
}
|
||||
}
|
||||
|
||||
func flagAsUnread() async -> Result<Void, RoomProxyError> {
|
||||
MXLog.info("Flagging room \(id) as unread")
|
||||
|
||||
do {
|
||||
try await room.setUnreadFlag(newValue: true)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed marking room \(id) as unread with error: \(error)")
|
||||
return .failure(.failedFlaggingAsUnread)
|
||||
}
|
||||
}
|
||||
|
||||
func flagAsRead() async -> Result<Void, RoomProxyError> {
|
||||
MXLog.info("Flagging room \(id) as read")
|
||||
|
||||
do {
|
||||
try await room.setUnreadFlag(newValue: false)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed marking room \(id) as read with error: \(error)")
|
||||
return .failure(.failedFlaggingAsRead)
|
||||
}
|
||||
}
|
||||
|
||||
func markAsRead(receiptType: ReceiptType) async -> Result<Void, RoomProxyError> {
|
||||
do {
|
||||
try await room.markAsRead(receiptType: receiptType)
|
||||
@@ -414,6 +396,40 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Room flags
|
||||
|
||||
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError> {
|
||||
MXLog.info("Flagging room \(id) as unread: \(isUnread)")
|
||||
|
||||
do {
|
||||
try await room.setUnreadFlag(newValue: isUnread)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed marking room \(id) as unread: \(isUnread) with error: \(error)")
|
||||
return .failure(.failedFlaggingAsUnread)
|
||||
}
|
||||
}
|
||||
|
||||
func getIsFavourite() async -> Result<Bool, RoomProxyError> {
|
||||
do {
|
||||
let result = try await room.roomInfo().isFavourite
|
||||
return .success(result)
|
||||
} catch {
|
||||
MXLog.error("Failed retrieving isFavourite for room: \(id) with error: \(error)")
|
||||
return .failure(.failedRetrievingIsFavourite)
|
||||
}
|
||||
}
|
||||
|
||||
func flagAsFavourite(_ isFavourite: Bool) async -> Result<Void, RoomProxyError> {
|
||||
do {
|
||||
try await room.setIsFavourite(isFavourite: isFavourite, tagOrder: nil)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed flagging room \(id) as favourite with error: \(error)")
|
||||
return .failure(.failedFlaggingAsFavourite)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Element Call
|
||||
|
||||
func canUserJoinCall(userID: String) async -> Result<Bool, RoomProxyError> {
|
||||
@@ -431,10 +447,10 @@ class RoomProxy: RoomProxyProtocol {
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func subscribeToRoomStateUpdates() {
|
||||
private func subscribeToRoomInfoUpdates() {
|
||||
roomInfoObservationToken = room.subscribeToRoomInfoUpdates(listener: RoomInfoUpdateListener { [weak self] in
|
||||
MXLog.info("Received room info update")
|
||||
self?.actionsSubject.send(.stateUpdate)
|
||||
self?.actionsSubject.send(.roomInfoUpdate)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -32,13 +32,14 @@ enum RoomProxyError: Error, Equatable {
|
||||
case failedUploadingAvatar
|
||||
case failedCheckingPermission
|
||||
case failedFlaggingAsUnread
|
||||
case failedFlaggingAsRead
|
||||
case failedMarkingAsRead
|
||||
case failedSendingTypingNotice
|
||||
case failedRetrievingIsFavourite
|
||||
case failedFlaggingAsFavourite
|
||||
}
|
||||
|
||||
enum RoomProxyAction {
|
||||
case stateUpdate
|
||||
case roomInfoUpdate
|
||||
}
|
||||
|
||||
// sourcery: AutoMockable
|
||||
@@ -48,6 +49,7 @@ protocol RoomProxyProtocol {
|
||||
var isPublic: Bool { get }
|
||||
var isSpace: Bool { get }
|
||||
var isEncrypted: Bool { get }
|
||||
var isFavourite: Bool { get async }
|
||||
var membership: Membership { get }
|
||||
var hasOngoingCall: Bool { get }
|
||||
var canonicalAlias: String? { get }
|
||||
@@ -109,15 +111,17 @@ protocol RoomProxyProtocol {
|
||||
|
||||
func canUserTriggerRoomNotification(userID: String) async -> Result<Bool, RoomProxyError>
|
||||
|
||||
func flagAsUnread() async -> Result<Void, RoomProxyError>
|
||||
|
||||
func flagAsRead() async -> Result<Void, RoomProxyError>
|
||||
|
||||
func markAsRead(receiptType: ReceiptType) async -> Result<Void, RoomProxyError>
|
||||
|
||||
/// https://spec.matrix.org/v1.9/client-server-api/#typing-notifications
|
||||
@discardableResult func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError>
|
||||
|
||||
// MARK: - Room Flags
|
||||
|
||||
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func flagAsFavourite(_ isFavourite: Bool) async -> Result<Void, RoomProxyError>
|
||||
|
||||
// MARK: - Element Call
|
||||
|
||||
func canUserJoinCall(userID: String) async -> Result<Bool, RoomProxyError>
|
||||
|
||||
@@ -83,98 +83,105 @@ extension Array where Element == RoomSummary {
|
||||
avatarURL: nil,
|
||||
lastMessage: AttributedString("I do not wish to take the trouble to understand mysticism"),
|
||||
lastMessageFormattedTimestamp: "14:56",
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 0,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 0,
|
||||
notificationMode: .allMessages,
|
||||
canonicalAlias: nil,
|
||||
inviter: nil,
|
||||
hasOngoingCall: false)),
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)),
|
||||
.filled(details: RoomSummaryDetails(id: "2",
|
||||
name: "Foundation and Empire",
|
||||
isDirect: true,
|
||||
avatarURL: URL.picturesDirectory,
|
||||
lastMessage: AttributedString("How do you see the Emperor then? You think he keeps office hours?"),
|
||||
lastMessageFormattedTimestamp: "2:56 PM",
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 2,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 2,
|
||||
notificationMode: .mute,
|
||||
canonicalAlias: nil,
|
||||
inviter: nil,
|
||||
hasOngoingCall: false)),
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)),
|
||||
.filled(details: RoomSummaryDetails(id: "3",
|
||||
name: "Second Foundation",
|
||||
isDirect: true,
|
||||
avatarURL: nil,
|
||||
lastMessage: try? AttributedString(markdown: "He certainly seemed no *mental genius* to me"),
|
||||
lastMessageFormattedTimestamp: "Some time ago",
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 3,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 0,
|
||||
notificationMode: .mentionsAndKeywordsOnly,
|
||||
canonicalAlias: nil,
|
||||
inviter: nil,
|
||||
hasOngoingCall: false)),
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)),
|
||||
.filled(details: RoomSummaryDetails(id: "4",
|
||||
name: "Foundation's Edge",
|
||||
isDirect: true,
|
||||
avatarURL: nil,
|
||||
lastMessage: AttributedString("There's an archaic measure of time that's called the month"),
|
||||
lastMessageFormattedTimestamp: "Just now",
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 2,
|
||||
unreadMentionsCount: 2,
|
||||
unreadNotificationsCount: 2,
|
||||
notificationMode: .allMessages,
|
||||
canonicalAlias: nil,
|
||||
inviter: nil,
|
||||
hasOngoingCall: false)),
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)),
|
||||
.filled(details: RoomSummaryDetails(id: "5",
|
||||
name: "Foundation and Earth",
|
||||
isDirect: true,
|
||||
avatarURL: nil,
|
||||
lastMessage: AttributedString("Clearly, if Earth is powerful enough to do that, it might also be capable of adjusting minds in order to force belief in its radioactivity"),
|
||||
lastMessageFormattedTimestamp: "1986",
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 1,
|
||||
unreadMentionsCount: 1,
|
||||
unreadNotificationsCount: 1,
|
||||
notificationMode: .allMessages,
|
||||
canonicalAlias: nil,
|
||||
inviter: nil,
|
||||
hasOngoingCall: true)),
|
||||
hasOngoingCall: true,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)),
|
||||
.filled(details: RoomSummaryDetails(id: "6",
|
||||
name: "Prelude to Foundation",
|
||||
isDirect: true,
|
||||
avatarURL: nil,
|
||||
lastMessage: AttributedString("Are you groping for the word 'paranoia'?"),
|
||||
lastMessageFormattedTimestamp: "きょうはじゅういちがつじゅういちにちです",
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 6,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 0,
|
||||
notificationMode: .mute,
|
||||
canonicalAlias: nil,
|
||||
inviter: nil,
|
||||
hasOngoingCall: true)),
|
||||
hasOngoingCall: true,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)),
|
||||
.filled(details: RoomSummaryDetails(id: "0",
|
||||
name: "Unknown",
|
||||
isDirect: false,
|
||||
avatarURL: nil,
|
||||
lastMessage: nil,
|
||||
lastMessageFormattedTimestamp: nil,
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 0,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 0,
|
||||
notificationMode: nil,
|
||||
canonicalAlias: nil,
|
||||
inviter: nil,
|
||||
hasOngoingCall: false)),
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)),
|
||||
.empty
|
||||
]
|
||||
|
||||
@@ -213,27 +220,29 @@ extension Array where Element == RoomSummary {
|
||||
avatarURL: URL.picturesDirectory,
|
||||
lastMessage: nil,
|
||||
lastMessageFormattedTimestamp: nil,
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 0,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 0,
|
||||
notificationMode: nil,
|
||||
canonicalAlias: "#footest:somewhere.org",
|
||||
inviter: RoomMemberProxyMock.mockCharlie,
|
||||
hasOngoingCall: false)),
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false)),
|
||||
.filled(details: RoomSummaryDetails(id: "someAwesomeRoomId2",
|
||||
name: "Second room",
|
||||
isDirect: true,
|
||||
avatarURL: nil,
|
||||
lastMessage: nil,
|
||||
lastMessageFormattedTimestamp: nil,
|
||||
isMarkedUnread: false,
|
||||
unreadMessagesCount: 0,
|
||||
unreadMentionsCount: 0,
|
||||
unreadNotificationsCount: 0,
|
||||
notificationMode: nil,
|
||||
canonicalAlias: nil,
|
||||
inviter: RoomMemberProxyMock.mockCharlie,
|
||||
hasOngoingCall: false))
|
||||
hasOngoingCall: false,
|
||||
isMarkedUnread: false,
|
||||
isFavourite: false))
|
||||
]
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ struct RoomSummaryDetails {
|
||||
let avatarURL: URL?
|
||||
let lastMessage: AttributedString?
|
||||
let lastMessageFormattedTimestamp: String?
|
||||
let isMarkedUnread: Bool
|
||||
let unreadMessagesCount: UInt
|
||||
let unreadMentionsCount: UInt
|
||||
let unreadNotificationsCount: UInt
|
||||
@@ -33,6 +32,9 @@ struct RoomSummaryDetails {
|
||||
let inviter: RoomMemberProxyProtocol?
|
||||
let hasOngoingCall: Bool
|
||||
|
||||
let isMarkedUnread: Bool
|
||||
let isFavourite: Bool
|
||||
|
||||
var hasUnreadMessages: Bool { unreadMessagesCount > 0 }
|
||||
var hasUnreadMentions: Bool { unreadMentionsCount > 0 }
|
||||
var hasUnreadNotifications: Bool { unreadNotificationsCount > 0 }
|
||||
@@ -60,7 +62,6 @@ extension RoomSummaryDetails {
|
||||
avatarURL = nil
|
||||
lastMessage = AttributedString(string)
|
||||
lastMessageFormattedTimestamp = "Now"
|
||||
isMarkedUnread = false
|
||||
unreadMessagesCount = hasUnreadMessages ? 1 : 0
|
||||
unreadMentionsCount = hasUnreadMentions ? 1 : 0
|
||||
unreadNotificationsCount = hasUnreadNotifications ? 1 : 0
|
||||
@@ -68,5 +69,8 @@ extension RoomSummaryDetails {
|
||||
canonicalAlias = nil
|
||||
inviter = nil
|
||||
hasOngoingCall = false
|
||||
|
||||
isMarkedUnread = false
|
||||
isFavourite = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,14 +252,15 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
|
||||
avatarURL: roomInfo.avatarUrl.flatMap(URL.init(string:)),
|
||||
lastMessage: attributedLastMessage,
|
||||
lastMessageFormattedTimestamp: lastMessageFormattedTimestamp,
|
||||
isMarkedUnread: appSettings.markAsUnreadEnabled ? roomInfo.isMarkedUnread : false,
|
||||
unreadMessagesCount: appSettings.mentionsBadgeEnabled ? UInt(roomInfo.numUnreadMessages) : 0,
|
||||
unreadMentionsCount: appSettings.mentionsBadgeEnabled ? UInt(roomInfo.numUnreadMentions) : 0,
|
||||
unreadNotificationsCount: appSettings.mentionsBadgeEnabled ? UInt(roomInfo.numUnreadNotifications) : UInt(roomInfo.notificationCount),
|
||||
notificationMode: notificationMode,
|
||||
canonicalAlias: roomInfo.canonicalAlias,
|
||||
inviter: inviterProxy,
|
||||
hasOngoingCall: roomInfo.hasRoomCall)
|
||||
hasOngoingCall: roomInfo.hasRoomCall,
|
||||
isMarkedUnread: appSettings.markAsUnreadEnabled ? roomInfo.isMarkedUnread : false,
|
||||
isFavourite: roomInfo.isFavourite)
|
||||
|
||||
return invalidated ? .invalidated(details: details) : .filled(details: details)
|
||||
}
|
||||
|
||||
@@ -590,6 +590,7 @@ class MockScreen: Identifiable {
|
||||
let coordinator = RoomDetailsScreenCoordinator(parameters: .init(accountUserID: "@owner:somewhere.com",
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
@@ -610,6 +611,7 @@ class MockScreen: Identifiable {
|
||||
let coordinator = RoomDetailsScreenCoordinator(parameters: .init(accountUserID: "@owner:somewhere.com",
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
@@ -632,6 +634,7 @@ class MockScreen: Identifiable {
|
||||
let coordinator = RoomDetailsScreenCoordinator(parameters: .init(accountUserID: "@owner:somewhere.com",
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
@@ -650,6 +653,7 @@ class MockScreen: Identifiable {
|
||||
let coordinator = RoomDetailsScreenCoordinator(parameters: .init(accountUserID: "@owner:somewhere.com",
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
@@ -669,6 +673,7 @@ class MockScreen: Identifiable {
|
||||
let coordinator = RoomDetailsScreenCoordinator(parameters: .init(accountUserID: "@owner:somewhere.com",
|
||||
roomProxy: roomProxy,
|
||||
mediaProvider: MockMediaProvider(),
|
||||
analyticsService: ServiceLocator.shared.analytics,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
notificationSettings: NotificationSettingsProxyMock(with: .init()),
|
||||
attributedStringBuilder: AttributedStringBuilder(permalinkBaseURL: ServiceLocator.shared.settings.permalinkBaseURL,
|
||||
|
||||
Reference in New Issue
Block a user