Room list notifications tweaks (#6106)

We decided against changing how unread activity is rendered in the room list, so the experiment and its developer option are no longer needed.
we have also added a notification settings entry for hiding the room list gray dots.
This commit is contained in:
Stefan Ceriu
2026-09-25 13:36:33 +03:00
committed by GitHub
parent cc07e07833
commit fc8ee9d93d
22 changed files with 49 additions and 84 deletions
@@ -1087,6 +1087,7 @@
"screen_notification_settings_mode_mentions" = "Mentions";
"screen_notification_settings_notification_section_title" = "Notify me for";
"screen_notification_settings_room_mention_label" = "Mentions of @room";
"screen_notification_settings_show_all_activity" = "Show all activity in the room list (dots or number of unread messages)";
"screen_notification_settings_sound_custom_fallback" = "Custom";
"screen_notification_settings_sound_custom_sound_button_title" = "Custom sound...";
"screen_notification_settings_sound_delete_sound_error_title" = "Error deleting file";
@@ -1087,6 +1087,7 @@
"screen_notification_settings_mode_mentions" = "Mentions";
"screen_notification_settings_notification_section_title" = "Notify me for";
"screen_notification_settings_room_mention_label" = "Mentions of @room";
"screen_notification_settings_show_all_activity" = "Show all activity in the room list (dots or number of unread messages)";
"screen_notification_settings_sound_custom_fallback" = "Custom";
"screen_notification_settings_sound_custom_sound_button_title" = "Custom sound...";
"screen_notification_settings_sound_delete_sound_error_title" = "Error deleting file";
@@ -1,4 +1,5 @@
"screen_home_tab_search" = "Search";
"screen_notification_settings_show_all_room_list_activity" = "Show all activity in the room list (dots or number of unread messages)";
"screen_search_empty_state_message" = "Search for chats and messages";
"screen_search_empty_state_title" = "Start searching...";
"screen_search_no_results_message" = "There are no results for “%1$@.” Try a new search term.";
@@ -354,8 +354,8 @@ final nonisolated class AppSettings: @unchecked Sendable {
// MARK: - Home Screen
@UserPreference(defaultValue: RoomListActivityVisibility.current)
var roomListActivityVisibility: RoomListActivityVisibility
@UserPreference(defaultValue: true)
var showAllRoomListActivity: Bool
// MARK: - Search Screen
@@ -1,15 +0,0 @@
//
// 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.
//
nonisolated 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
}
@@ -12,6 +12,8 @@ import Foundation
internal nonisolated enum UntranslatedL10n {
/// Search
internal static var screenHomeTabSearch: String { return UntranslatedL10n.tr("Untranslated", "screen_home_tab_search") }
/// Show all activity in the room list (dots or number of unread messages)
internal static var screenNotificationSettingsShowAllRoomListActivity: String { return UntranslatedL10n.tr("Untranslated", "screen_notification_settings_show_all_room_list_activity") }
/// Search for chats and messages
internal static var screenSearchEmptyStateMessage: String { return UntranslatedL10n.tr("Untranslated", "screen_search_empty_state_message") }
/// Start searching...
+2
View File
@@ -2544,6 +2544,8 @@ internal nonisolated enum L10n {
internal static var screenNotificationSettingsNotificationSectionTitle: String { return L10n.tr("Localizable", "screen_notification_settings_notification_section_title") }
/// Mentions of @room
internal static var screenNotificationSettingsRoomMentionLabel: String { return L10n.tr("Localizable", "screen_notification_settings_room_mention_label") }
/// Show all activity in the room list (dots or number of unread messages)
internal static var screenNotificationSettingsShowAllActivity: String { return L10n.tr("Localizable", "screen_notification_settings_show_all_activity") }
/// Custom
internal static var screenNotificationSettingsSoundCustomFallback: String { return L10n.tr("Localizable", "screen_notification_settings_sound_custom_fallback") }
/// Custom sound...
@@ -104,8 +104,6 @@ struct HomeScreenViewState: BindableState {
var hideInviteAvatars = false
var roomListActivityVisibility: RoomListActivityVisibility = .current
var reportRoomEnabled = false
var shouldShowSpaceFilters = false
@@ -199,8 +197,6 @@ struct HomeScreenRoom: Identifiable, Equatable {
let callBadgeType: CallBadgeType
}
var hasUnreads = false
let name: String
let isDirect: Bool
@@ -255,16 +251,15 @@ struct HomeScreenRoom: Identifiable, Equatable {
extension HomeScreenRoom {
init(summary: RoomSummary,
roomListActivityVisibility: RoomListActivityVisibility = .current,
showAllActivity: Bool = true,
seenInvites: Set<String> = []) {
let roomID = summary.id
let isUnseenInvite = summary.joinRequestType?.isInvite == true && !seenInvites.contains(roomID)
let isDotShown = switch roomListActivityVisibility {
case .current:
let isDotShown = if showAllActivity {
summary.hasUnreadMessages || summary.hasUnreadMentions || summary.hasUnreadNotifications || summary.isMarkedUnread || isUnseenInvite
case .hide, .show:
} else {
(!summary.isMuted && (summary.hasUnreadNotifications || summary.hasUnreadMentions)) || summary.isMarkedUnread || isUnseenInvite
}
@@ -292,7 +287,6 @@ extension HomeScreenRoom {
isMentionShown: isMentionShown,
isMuteShown: isMuteShown,
callBadgeType: callBadge),
hasUnreads: summary.hasUnreadMessages,
name: summary.name,
isDirect: summary.isDirect,
isHighlighted: isHighlighted,
@@ -113,9 +113,9 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
.weakAssign(to: \.state.selectedRoomID, on: self)
.store(in: &cancellables)
appSettings.roomListActivityVisibilityPublisher
.sink { [weak self] value in
self?.state.roomListActivityVisibility = value
appSettings.showAllRoomListActivityPublisher
.removeDuplicates()
.sink { [weak self] _ in
self?.updateRooms()
}
.store(in: &cancellables)
@@ -376,7 +376,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
for summary in roomSummaryProvider.roomListPublisher.value {
let room = HomeScreenRoom(summary: summary,
roomListActivityVisibility: appSettings.roomListActivityVisibility,
showAllActivity: appSettings.showAllRoomListActivity,
seenInvites: seenInvites)
rooms.append(room)
}
@@ -15,7 +15,6 @@ 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
@@ -82,7 +81,7 @@ struct HomeScreenRoomCell: View {
Text(String(statusEmoji))
}
}
.font(headerFont)
.font(.compound.bodyLGSemibold)
.foregroundColor(.compound.textPrimary)
.frame(maxWidth: .infinity, alignment: .leading)
@@ -94,17 +93,6 @@ struct HomeScreenRoomCell: View {
}
}
private var headerFont: Font {
switch roomListActivityVisibility {
case .current:
.compound.bodyLGSemibold
case .show:
room.hasUnreads ? .compound.bodyLGSemibold : .compound.bodyLG
case .hide:
room.isHighlighted ? .compound.bodyLGSemibold : .compound.bodyLG
}
}
private var footer: some View {
HStack(alignment: .firstTextBaseline, spacing: 0) {
ZStack(alignment: .topLeading) {
@@ -190,21 +178,10 @@ struct HomeScreenRoomCell: View {
private var lastMessage: some View {
if let displayedLastMessage = room.displayedLastMessage {
Text(displayedLastMessage)
.font(lastMessageFont)
.font(.compound.bodyMD)
.lastMessageFormatting(hasFailed: room.lastMessageState == .failed)
}
}
private var lastMessageFont: Font {
switch roomListActivityVisibility {
case .current:
.compound.bodyMD
case .show:
room.hasUnreads ? .compound.bodyMDSemibold : .compound.bodyMD
case .hide:
room.isHighlighted ? .compound.bodyMDSemibold : .compound.bodyMD
}
}
}
struct HomeScreenRoomCellButtonStyle: ButtonStyle {
@@ -36,7 +36,6 @@ struct HomeScreenRoomList: View {
let isSelected = context.viewState.selectedRoomID == room.id
HomeScreenRoomCell(room: room,
roomListActivityVisibility: context.viewState.roomListActivityVisibility,
isSelected: isSelected,
mediaProvider: context.mediaProvider,
action: context.send)
@@ -57,7 +57,6 @@ protocol DeveloperOptionsProtocol: AnyObject {
var hideQuietNotificationAlerts: Bool { get set }
var focusEventOnNotificationTap: Bool { get set }
var roomListActivityVisibility: RoomListActivityVisibility { get set }
var elementCallBaseURLOverride: URL? { get set }
var fuzzyRoomListSearchEnabled: Bool { get set }
@@ -60,13 +60,6 @@ struct DeveloperOptionsScreen: View {
}
Section("Room List") {
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) {
Text("Fuzzy searching")
}
@@ -40,6 +40,7 @@ struct NotificationSettingsScreenViewStateBindings {
var roomMentionsEnabled = false
var callsEnabled = false
var invitationsEnabled = false
var showAllRoomListActivity = true
var alertInfo: AlertInfo<NotificationSettingsScreenErrorType>?
var shouldShowAlertSounds = false
var shouldShowCustomAlertTonePicker = false
@@ -93,6 +94,7 @@ enum NotificationSettingsScreenViewAction {
case roomMentionChanged
case callsChanged
case invitationsChanged
case showAllRoomListActivityChanged
case close
case fixConfigurationMismatchTapped
case selectAlertTone(NotificationTone)
@@ -38,7 +38,8 @@ class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelTy
notificationTonePreviewer = AudioPlayer()
self.notificationToneManager = notificationToneManager
let bindings = NotificationSettingsScreenViewStateBindings(enableNotifications: appSettings.enableNotifications)
let bindings = NotificationSettingsScreenViewStateBindings(enableNotifications: appSettings.enableNotifications,
showAllRoomListActivity: appSettings.showAllRoomListActivity)
super.init(initialViewState: NotificationSettingsScreenViewState(bindings: bindings,
isModallyPresented: isModallyPresented,
selectedAlertTone: appSettings.selectedNotificationTone ?? NotificationToneManager.defaultElementXMessageTone,
@@ -102,6 +103,8 @@ class NotificationSettingsScreenViewModel: NotificationSettingsScreenViewModelTy
return
}
Task { await enableInvitations(state.bindings.invitationsEnabled) }
case .showAllRoomListActivityChanged:
appSettings.showAllRoomListActivity = state.bindings.showAllRoomListActivity
case .close:
actionsSubject.send(.close)
case .fixConfigurationMismatchTapped:
@@ -26,7 +26,11 @@ struct NotificationSettingsScreen: View {
if context.enableNotifications {
roomsNotificationSection
}
roomListActivitySection
if context.enableNotifications {
if context.viewState.showCallsSettings, context.viewState.settings?.callsEnabled != nil {
callsSection
}
@@ -139,6 +143,16 @@ struct NotificationSettingsScreen: View {
}
}
private var roomListActivitySection: some View {
Section {
ListRow(label: .plain(title: L10n.screenNotificationSettingsShowAllActivity),
kind: .toggle($context.showAllRoomListActivity))
.onChange(of: context.showAllRoomListActivity) {
context.send(viewAction: .showAllRoomListActivityChanged)
}
}
}
private var callsSection: some View {
Section {
ListRow(label: .plain(title: L10n.screenNotificationSettingsCallsLabel),