mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Notification Decoration Revised (#5312)
1. I removed the grey dots for when there is activity in rooms set to mentions or mute. 2. For all unread rooms, I made the message preview text bold for better legibility 3. For rooms with no unreads, I made the font weight regular, again for legibility We have also mergeg the new room list activity rendering with the existing feature hide unread badge feature flag and provide 3 variations: current production behavior, no badge but bolding, and no bolding and no badge
This commit is contained in:
@@ -84,7 +84,7 @@ final class AppSettings {
|
||||
case automaticBackPaginationEnabled
|
||||
|
||||
// Doug's tweaks 🔧
|
||||
case hideUnreadMessagesBadge
|
||||
case roomListActivityVisibility
|
||||
case hideQuietNotificationAlerts
|
||||
|
||||
case developerOptionsEnabled
|
||||
@@ -358,8 +358,8 @@ final class AppSettings {
|
||||
|
||||
// MARK: - Home Screen
|
||||
|
||||
@UserPreference(key: UserDefaultsKeys.hideUnreadMessagesBadge, defaultValue: false, storageType: .userDefaults(store))
|
||||
var hideUnreadMessagesBadge
|
||||
@UserPreference(key: UserDefaultsKeys.roomListActivityVisibility, defaultValue: .current, storageType: .userDefaults(store))
|
||||
var roomListActivityVisibility: RoomListActivityVisibility
|
||||
|
||||
// MARK: - Room Screen
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
enum RoomListActivityVisibility: String, CaseIterable, Codable {
|
||||
/// Show unread badges for all unread messages (the default).
|
||||
case current
|
||||
/// Don't show badges but bold unread room names and their latest message
|
||||
case show
|
||||
/// Don't show badges and don't bold room names and messages
|
||||
case hide
|
||||
}
|
||||
@@ -108,6 +108,8 @@ struct HomeScreenViewState: BindableState {
|
||||
|
||||
var hideInviteAvatars = false
|
||||
|
||||
var roomListActivityVisibility: RoomListActivityVisibility = .current
|
||||
|
||||
var reportRoomEnabled = false
|
||||
|
||||
var shouldShowSpaceFilters = false
|
||||
@@ -197,6 +199,8 @@ struct HomeScreenRoom: Identifiable, Equatable {
|
||||
let callBadgeType: CallBadgeType
|
||||
}
|
||||
|
||||
var hasUnreads = false
|
||||
|
||||
let name: String
|
||||
|
||||
let isDirect: Bool
|
||||
@@ -247,13 +251,20 @@ struct HomeScreenRoom: Identifiable, Equatable {
|
||||
}
|
||||
|
||||
extension HomeScreenRoom {
|
||||
init(summary: RoomSummary, hideUnreadMessagesBadge: Bool, seenInvites: Set<String> = []) {
|
||||
init(summary: RoomSummary,
|
||||
roomListActivityVisibility: RoomListActivityVisibility = .current,
|
||||
seenInvites: Set<String> = []) {
|
||||
let roomID = summary.id
|
||||
|
||||
let hasUnreadMessages = hideUnreadMessagesBadge ? false : summary.hasUnreadMessages
|
||||
let isUnseenInvite = summary.joinRequestType?.isInvite == true && !seenInvites.contains(roomID)
|
||||
|
||||
let isDotShown = hasUnreadMessages || summary.hasUnreadMentions || summary.hasUnreadNotifications || summary.isMarkedUnread || isUnseenInvite
|
||||
|
||||
let isDotShown = switch roomListActivityVisibility {
|
||||
case .current:
|
||||
summary.hasUnreadMessages || summary.hasUnreadMentions || summary.hasUnreadNotifications || summary.isMarkedUnread || isUnseenInvite
|
||||
case .hide, .show:
|
||||
(!summary.isMuted && (summary.hasUnreadNotifications || summary.hasUnreadMentions)) || summary.isMarkedUnread || isUnseenInvite
|
||||
}
|
||||
|
||||
let isMentionShown = summary.hasUnreadMentions && !summary.isMuted
|
||||
let isMuteShown = summary.isMuted
|
||||
let isHighlighted = summary.isMarkedUnread || (!summary.isMuted && (summary.hasUnreadNotifications || summary.hasUnreadMentions)) || isUnseenInvite
|
||||
@@ -275,6 +286,7 @@ extension HomeScreenRoom {
|
||||
isMentionShown: isMentionShown,
|
||||
isMuteShown: isMuteShown,
|
||||
callBadgeType: callBadge),
|
||||
hasUnreads: summary.hasUnreadMessages,
|
||||
name: summary.name,
|
||||
isDirect: summary.isDirect,
|
||||
isHighlighted: isHighlighted,
|
||||
|
||||
@@ -114,8 +114,11 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
.weakAssign(to: \.state.selectedRoomID, on: self)
|
||||
.store(in: &cancellables)
|
||||
|
||||
appSettings.$hideUnreadMessagesBadge
|
||||
.sink { [weak self] _ in self?.updateRooms() }
|
||||
appSettings.$roomListActivityVisibility
|
||||
.sink { [weak self] value in
|
||||
self?.state.roomListActivityVisibility = value
|
||||
self?.updateRooms()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
appSettings.$seenInvites
|
||||
@@ -363,7 +366,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
|
||||
for summary in roomSummaryProvider.roomListPublisher.value {
|
||||
let room = HomeScreenRoom(summary: summary,
|
||||
hideUnreadMessagesBadge: appSettings.hideUnreadMessagesBadge,
|
||||
roomListActivityVisibility: appSettings.roomListActivityVisibility,
|
||||
seenInvites: seenInvites)
|
||||
rooms.append(room)
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ private extension HomeScreenRoom {
|
||||
isFavourite: false,
|
||||
isTombstoned: false)
|
||||
|
||||
return .init(summary: summary, hideUnreadMessagesBadge: false)
|
||||
return .init(summary: summary)
|
||||
}
|
||||
|
||||
static func invite(name: String = "Awesome Room",
|
||||
@@ -276,6 +276,6 @@ private extension HomeScreenRoom {
|
||||
isFavourite: false,
|
||||
isTombstoned: false)
|
||||
|
||||
return .init(summary: summary, hideUnreadMessagesBadge: false)
|
||||
return .init(summary: summary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,7 +172,7 @@ private extension HomeScreenRoom {
|
||||
isFavourite: false,
|
||||
isTombstoned: false)
|
||||
|
||||
return .init(summary: summary, hideUnreadMessagesBadge: false)
|
||||
return .init(summary: summary)
|
||||
}
|
||||
|
||||
static func roomKnocked(alias: String? = nil, avatarURL: URL? = nil) -> HomeScreenRoom {
|
||||
@@ -205,6 +205,6 @@ private extension HomeScreenRoom {
|
||||
isFavourite: false,
|
||||
isTombstoned: false)
|
||||
|
||||
return .init(summary: summary, hideUnreadMessagesBadge: false)
|
||||
return .init(summary: summary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ struct HomeScreenRoomCell: View {
|
||||
@Environment(\.redactionReasons) private var redactionReasons
|
||||
|
||||
let room: HomeScreenRoom
|
||||
var roomListActivityVisibility: RoomListActivityVisibility = .current
|
||||
let isSelected: Bool
|
||||
let mediaProvider: MediaProviderProtocol!
|
||||
let action: (HomeScreenViewAction) -> Void
|
||||
@@ -74,7 +75,7 @@ struct HomeScreenRoomCell: View {
|
||||
private var header: some View {
|
||||
HStack(alignment: .top, spacing: 16) {
|
||||
Text(room.name)
|
||||
.font(.compound.bodyLGSemibold)
|
||||
.font(headerFont)
|
||||
.foregroundColor(.compound.textPrimary)
|
||||
.lineLimit(1)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
@@ -87,6 +88,17 @@ struct HomeScreenRoomCell: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var headerFont: Font {
|
||||
switch roomListActivityVisibility {
|
||||
case .current:
|
||||
.compound.bodyLGSemibold
|
||||
case .show:
|
||||
room.hasUnreads ? .compound.bodyLGSemibold : .compound.bodyLG
|
||||
case .hide:
|
||||
.compound.bodyLG
|
||||
}
|
||||
}
|
||||
|
||||
private var footer: some View {
|
||||
HStack(alignment: .firstTextBaseline, spacing: 0) {
|
||||
ZStack(alignment: .topLeading) {
|
||||
@@ -157,6 +169,7 @@ struct HomeScreenRoomCell: View {
|
||||
private var lastMessage: some View {
|
||||
if let displayedLastMessage = room.displayedLastMessage {
|
||||
Text(displayedLastMessage)
|
||||
.font(roomListActivityVisibility == .show ? (room.hasUnreads ? .compound.bodyMDSemibold : .compound.bodyMD) : .compound.bodyMD)
|
||||
.lastMessageFormatting(hasFailed: room.lastMessageState == .failed)
|
||||
}
|
||||
}
|
||||
@@ -175,8 +188,7 @@ struct HomeScreenRoomCellButtonStyle: ButtonStyle {
|
||||
|
||||
private extension View {
|
||||
func lastMessageFormatting(hasFailed: Bool) -> some View {
|
||||
font(.compound.bodyMD)
|
||||
.foregroundColor(hasFailed ? .compound.textCriticalPrimary : .compound.textSecondary)
|
||||
foregroundColor(hasFailed ? .compound.textCriticalPrimary : .compound.textSecondary)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.leading)
|
||||
}
|
||||
@@ -224,7 +236,7 @@ struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
|
||||
}
|
||||
|
||||
static func mockRoom(summary: RoomSummary) -> HomeScreenRoom? {
|
||||
HomeScreenRoom(summary: summary, hideUnreadMessagesBadge: false)
|
||||
HomeScreenRoom(summary: summary)
|
||||
}
|
||||
|
||||
static func makeViewModel(roomSummaryProvider: RoomSummaryProviderProtocol) -> HomeScreenViewModel {
|
||||
@@ -263,6 +275,6 @@ struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
|
||||
isFavourite: false,
|
||||
isTombstoned: false)
|
||||
|
||||
return .init(summary: summary, hideUnreadMessagesBadge: false)
|
||||
return .init(summary: summary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,11 @@ struct HomeScreenRoomList: View {
|
||||
case .room:
|
||||
let isSelected = context.viewState.selectedRoomID == room.id
|
||||
|
||||
HomeScreenRoomCell(room: room, isSelected: isSelected, mediaProvider: context.mediaProvider, action: context.send)
|
||||
HomeScreenRoomCell(room: room,
|
||||
roomListActivityVisibility: context.viewState.roomListActivityVisibility,
|
||||
isSelected: isSelected,
|
||||
mediaProvider: context.mediaProvider,
|
||||
action: context.send)
|
||||
.simultaneousGesture(TapGesture(count: 2).onEnded {
|
||||
context.send(viewAction: .detachRoom(roomIdentifier: room.id))
|
||||
})
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
|
||||
var focusEventOnNotificationTap: Bool { get set }
|
||||
var automaticBackPaginationEnabled: Bool { get set }
|
||||
|
||||
var hideUnreadMessagesBadge: Bool { get set }
|
||||
var roomListActivityVisibility: RoomListActivityVisibility { get set }
|
||||
var elementCallBaseURLOverride: URL? { get set }
|
||||
|
||||
var publicSearchEnabled: Bool { get set }
|
||||
|
||||
+5
-2
@@ -56,8 +56,11 @@ struct DeveloperOptionsScreen: View {
|
||||
Text("Public search")
|
||||
}
|
||||
|
||||
Toggle(isOn: $context.hideUnreadMessagesBadge) {
|
||||
Text("Hide grey dots")
|
||||
Picker("Room list activity visibility", selection: $context.roomListActivityVisibility) {
|
||||
ForEach(RoomListActivityVisibility.allCases, id: \.self) { visibility in
|
||||
Text(visibility.rawValue.capitalized)
|
||||
.tag(visibility)
|
||||
}
|
||||
}
|
||||
|
||||
Toggle(isOn: $context.fuzzyRoomListSearchEnabled) {
|
||||
|
||||
Reference in New Issue
Block a user