mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
MentionBadge FF (#2281)
This commit is contained in:
@@ -147,6 +147,8 @@ struct HomeScreenRoom: Identifiable, Equatable {
|
||||
|
||||
var hasUnreads = false
|
||||
|
||||
var hasMentions = false
|
||||
|
||||
var hasOngoingCall = false
|
||||
|
||||
var timestamp: String?
|
||||
@@ -164,6 +166,7 @@ struct HomeScreenRoom: Identifiable, Equatable {
|
||||
roomId: nil,
|
||||
name: "Placeholder room name",
|
||||
hasUnreads: false,
|
||||
hasMentions: false,
|
||||
timestamp: "Now",
|
||||
lastMessage: placeholderLastMessage,
|
||||
isPlaceholder: true)
|
||||
|
||||
@@ -287,18 +287,18 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
|
||||
private func buildRoom(with details: RoomSummaryDetails, invalidated: Bool) -> HomeScreenRoom {
|
||||
let identifier = invalidated ? "invalidated-" + details.id : details.id
|
||||
|
||||
let notificationMode = details.notificationMode == .allMessages ? nil : details.notificationMode
|
||||
let hasMentions = appSettings.mentionsBadgeEnabled ? details.unreadMentionsCount > 0 : false
|
||||
|
||||
return HomeScreenRoom(id: identifier,
|
||||
roomId: details.id,
|
||||
name: details.name,
|
||||
hasUnreads: details.unreadNotificationCount > 0,
|
||||
hasUnreads: details.unreadMessagesCount > 0,
|
||||
hasMentions: hasMentions,
|
||||
hasOngoingCall: details.hasOngoingCall,
|
||||
timestamp: details.lastMessageFormattedTimestamp,
|
||||
lastMessage: details.lastMessage,
|
||||
avatarURL: details.avatarURL,
|
||||
notificationMode: notificationMode)
|
||||
notificationMode: details.notificationMode)
|
||||
}
|
||||
|
||||
private func updateVisibleRange(_ range: Range<Int>) {
|
||||
|
||||
@@ -95,8 +95,8 @@ struct HomeScreenRoomCell: View {
|
||||
|
||||
if let timestamp = room.timestamp {
|
||||
Text(timestamp)
|
||||
.font(room.hasUnreads ? .compound.bodySMSemibold : .compound.bodySM)
|
||||
.foregroundColor(room.hasUnreads ? .compound.textActionAccent : .compound.textSecondary)
|
||||
.font(isHighlighted ? .compound.bodySMSemibold : .compound.bodySM)
|
||||
.foregroundColor(isHighlighted ? .compound.textActionAccent : .compound.textSecondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,33 +119,48 @@ struct HomeScreenRoomCell: View {
|
||||
HStack(spacing: 8) {
|
||||
if room.hasOngoingCall {
|
||||
CompoundIcon(\.videoCallSolid, size: .xSmall, relativeTo: .compound.bodySM)
|
||||
.foregroundColor(room.hasUnreads ? .compound.iconAccentTertiary : .compound.iconQuaternary)
|
||||
.foregroundColor(isHighlighted ? .compound.iconAccentTertiary : .compound.iconQuaternary)
|
||||
}
|
||||
|
||||
if room.notificationMode == .mute {
|
||||
CompoundIcon(\.notificationsSolidOff, size: .custom(15), relativeTo: .compound.bodyMD)
|
||||
.accessibilityLabel(L10n.a11yNotificationsMuted)
|
||||
.foregroundColor(.compound.iconQuaternary)
|
||||
}
|
||||
|
||||
notificationModeIcon
|
||||
.foregroundColor(room.hasUnreads ? .compound.iconAccentTertiary : .compound.iconQuaternary)
|
||||
if room.hasMentions, room.notificationMode != .mute {
|
||||
mentionIcon
|
||||
.foregroundColor(.compound.iconAccentTertiary)
|
||||
}
|
||||
|
||||
if room.hasUnreads {
|
||||
if hasNewContent {
|
||||
Circle()
|
||||
.frame(width: 12, height: 12)
|
||||
.foregroundColor(.compound.iconAccentTertiary)
|
||||
.foregroundColor(isHighlighted ? .compound.iconAccentTertiary : .compound.iconQuaternary)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var notificationModeIcon: some View {
|
||||
switch room.notificationMode {
|
||||
case .none, .allMessages:
|
||||
EmptyView()
|
||||
case .mentionsAndKeywordsOnly:
|
||||
CompoundIcon(\.mention, size: .custom(15), relativeTo: .compound.bodyMD)
|
||||
.accessibilityLabel(L10n.a11yNotificationsMentionsOnly)
|
||||
case .mute:
|
||||
CompoundIcon(\.notificationsSolidOff, size: .custom(15), relativeTo: .compound.bodyMD)
|
||||
.accessibilityLabel(L10n.a11yNotificationsMuted)
|
||||
private var hasNewContent: Bool {
|
||||
room.hasUnreads || room.hasMentions
|
||||
}
|
||||
|
||||
private var isHighlighted: Bool {
|
||||
guard !room.isPlaceholder else {
|
||||
return false
|
||||
}
|
||||
return (isNotificationModeUnrestricted && hasNewContent) ||
|
||||
(room.notificationMode == .mentionsAndKeywordsOnly && room.hasMentions)
|
||||
}
|
||||
|
||||
private var isNotificationModeUnrestricted: Bool {
|
||||
room.notificationMode == nil || room.notificationMode == .allMessages
|
||||
}
|
||||
|
||||
private var mentionIcon: some View {
|
||||
CompoundIcon(\.mention, size: .custom(15), relativeTo: .compound.bodyMD)
|
||||
.accessibilityLabel(L10n.a11yNotificationsMentionsOnly)
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@@ -178,41 +193,67 @@ private extension View {
|
||||
}
|
||||
|
||||
struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
|
||||
static var previews: some View {
|
||||
let summaryProvider = MockRoomSummaryProvider(state: .loaded(.mockRooms))
|
||||
|
||||
let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "John Doe", roomSummaryProvider: summaryProvider),
|
||||
static let summaryProviderGeneric = MockRoomSummaryProvider(state: .loaded(.mockRooms))
|
||||
static let viewModelGeneric = {
|
||||
let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "John Doe", roomSummaryProvider: summaryProviderGeneric),
|
||||
mediaProvider: MockMediaProvider(),
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
let viewModel = HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
|
||||
let rooms: [HomeScreenRoom] = summaryProvider.roomListPublisher.value.compactMap { summary -> HomeScreenRoom? in
|
||||
switch summary {
|
||||
case .empty:
|
||||
return nil
|
||||
case .invalidated(let details), .filled(let details):
|
||||
return HomeScreenRoom(id: UUID().uuidString,
|
||||
roomId: details.id,
|
||||
name: details.name,
|
||||
hasUnreads: details.unreadNotificationCount > 0,
|
||||
hasOngoingCall: details.hasOngoingCall,
|
||||
timestamp: Date(timeIntervalSinceReferenceDate: 0).formattedMinimal(),
|
||||
lastMessage: details.lastMessage,
|
||||
notificationMode: details.notificationMode)
|
||||
}
|
||||
}
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}()
|
||||
|
||||
static let summaryProviderForNotificationsState = MockRoomSummaryProvider(state: .loaded(.mockRoomsWithNotificationsState))
|
||||
static let viewModelForNotificationsState = {
|
||||
let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "John Doe", roomSummaryProvider: summaryProviderForNotificationsState),
|
||||
mediaProvider: MockMediaProvider(),
|
||||
voiceMessageMediaManager: VoiceMessageMediaManagerMock())
|
||||
|
||||
return VStack(spacing: 0) {
|
||||
ForEach(rooms) { room in
|
||||
HomeScreenRoomCell(room: room, context: viewModel.context, isSelected: false)
|
||||
}
|
||||
|
||||
HomeScreenRoomCell(room: .placeholder(), context: viewModel.context, isSelected: false)
|
||||
.redacted(reason: .placeholder)
|
||||
return HomeScreenViewModel(userSession: userSession,
|
||||
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
|
||||
appSettings: ServiceLocator.shared.settings,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController)
|
||||
}()
|
||||
|
||||
static func mockRoom(summary: RoomSummary) -> HomeScreenRoom? {
|
||||
switch summary {
|
||||
case .empty:
|
||||
return nil
|
||||
case .invalidated(let details), .filled(let details):
|
||||
return HomeScreenRoom(id: UUID().uuidString,
|
||||
roomId: details.id,
|
||||
name: details.name,
|
||||
hasUnreads: details.unreadMessagesCount > 0, hasMentions: details.unreadMentionsCount > 0,
|
||||
hasOngoingCall: details.hasOngoingCall,
|
||||
timestamp: Date(timeIntervalSinceReferenceDate: 0).formattedMinimal(),
|
||||
lastMessage: details.lastMessage,
|
||||
notificationMode: details.notificationMode)
|
||||
}
|
||||
}
|
||||
|
||||
static var previews: some View {
|
||||
let genericRooms: [HomeScreenRoom] = summaryProviderGeneric.roomListPublisher.value.compactMap(mockRoom)
|
||||
|
||||
let notificationsStateRooms: [HomeScreenRoom] = summaryProviderForNotificationsState.roomListPublisher.value.compactMap(mockRoom)
|
||||
|
||||
VStack(spacing: 0) {
|
||||
ForEach(genericRooms) { room in
|
||||
HomeScreenRoomCell(room: room, context: viewModelGeneric.context, isSelected: false)
|
||||
}
|
||||
|
||||
HomeScreenRoomCell(room: .placeholder(), context: viewModelGeneric.context, isSelected: false)
|
||||
.redacted(reason: .placeholder)
|
||||
}
|
||||
.previewDisplayName("Generic")
|
||||
|
||||
VStack(spacing: 0) {
|
||||
ForEach(notificationsStateRooms) { room in
|
||||
HomeScreenRoomCell(room: room, context: viewModelForNotificationsState.context, isSelected: false)
|
||||
}
|
||||
}
|
||||
.previewLayout(.sizeThatFits)
|
||||
.previewDisplayName("Notifications State")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user