From e0c380547e7c503e272aae76b1c806100b6047f7 Mon Sep 17 00:00:00 2001 From: Narasimha-sc <166327228+Narasimha-sc@users.noreply.github.com> Date: Sat, 29 Aug 2026 05:37:38 +0000 Subject: [PATCH] ui: highlight the chat list filter button while this profile has unread The unread filter button looked identical whether or not there was anything to filter for, so nothing suggested that switching it on would show something. Tint it with the accent colour while the current profile's unread count is above zero - the same per-profile count the profile picker shows - and give it the pill the active state already draws, as a 12% accent fill behind a 40% accent hairline ring. The three states then read as one progression: grey strokes, accent strokes on a faint pill, solid accent pill when the filter is on. Tinting alone was too easy to miss on 16sp strokes, and adding the pill outline gives the change a shape rather than only a hue. On iOS the ring comes from the SF Symbol variants, so the button steps through line.3.horizontal.decrease, .circle and .circle.fill. --- .../Shared/Views/ChatList/ChatListView.swift | 15 +++++++++--- apps/ios/product/views/chat-list.md | 1 + .../common/views/chatlist/ChatListView.kt | 23 ++++++++++++++++--- apps/multiplatform/product/views/chat-list.md | 2 +- 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index b05e0696e3..6f8bf8aa39 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -764,14 +764,23 @@ struct ChatListSearchBar: View { private func toggleFilterButton() -> some View { let showUnread = chatTagsModel.activeFilter == .unread + let currentUserUnread = m.users.contains { $0.user.activeUser && $0.unreadCount > 0 } + let highlight = showUnread || currentUserUnread + let symbol = if showUnread { + "line.3.horizontal.decrease.circle.fill" + } else if currentUserUnread { + "line.3.horizontal.decrease.circle" + } else { + "line.3.horizontal.decrease" + } return ZStack { Color.clear .frame(width: 22, height: 22) - Image(systemName: showUnread ? "line.3.horizontal.decrease.circle.fill" : "line.3.horizontal.decrease") + Image(systemName: symbol) .resizable() .scaledToFit() - .foregroundColor(showUnread ? theme.colors.primary : theme.colors.secondary) - .frame(width: showUnread ? 22 : 16, height: showUnread ? 22 : 16) + .foregroundColor(highlight ? theme.colors.primary : theme.colors.secondary) + .frame(width: highlight ? 22 : 16, height: highlight ? 22 : 16) .onTapGesture { if chatTagsModel.activeFilter == .unread { chatTagsModel.activeFilter = nil diff --git a/apps/ios/product/views/chat-list.md b/apps/ios/product/views/chat-list.md index 04d19bef9e..26c816116f 100644 --- a/apps/ios/product/views/chat-list.md +++ b/apps/ios/product/views/chat-list.md @@ -33,6 +33,7 @@ The toolbar supports two layout modes: - When active, `searchMode = true` hides the navigation bar and shows inline search - Filters chat list in real-time by contact/group name and message content - Detects pasted SimpleX links (`searchShowingSimplexLink`) and offers to connect +- Unread filter toggle button at the trailing edge while search is unfocused and the list is non-empty; highlighted while the current profile has unread ### Chat Filter Tabs (Tags) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 68fa25d553..168d27533c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -709,6 +709,7 @@ private fun BoxScope.unreadBadge(text: String? = "") { @Composable private fun ToggleFilterEnabledButton() { val showUnread = remember { chatModel.activeChatTagFilter }.value == ActiveFilter.Unread + val currentUserUnread = chatModel.users.any { it.user.activeUser && it.unreadCount > 0 } IconButton(onClick = { if (showUnread) { @@ -718,14 +719,30 @@ private fun ToggleFilterEnabledButton() { } }) { val sp16 = with(LocalDensity.current) { 16.sp.toDp() } + val primary = MaterialTheme.colors.primary + val tint = when { + showUnread -> MaterialTheme.colors.background + currentUserUnread -> primary + else -> MaterialTheme.colors.secondary + } + val fill = when { + showUnread -> primary + currentUserUnread -> primary.copy(alpha = 0.12f) + else -> Color.Unspecified + } + val stroke = when { + showUnread -> primary + currentUserUnread -> primary.copy(alpha = 0.4f) + else -> Color.Unspecified + } Icon( painterResource(MR.images.ic_filter_list), null, - tint = if (showUnread) MaterialTheme.colors.background else MaterialTheme.colors.secondary, + tint = tint, modifier = Modifier .padding(3.dp) - .background(color = if (showUnread) MaterialTheme.colors.primary else Color.Unspecified, shape = RoundedCornerShape(50)) - .border(width = 1.dp, color = if (showUnread) MaterialTheme.colors.primary else Color.Unspecified, shape = RoundedCornerShape(50)) + .background(color = fill, shape = RoundedCornerShape(50)) + .border(width = 1.dp, color = stroke, shape = RoundedCornerShape(50)) .padding(3.dp) .size(sp16) ) diff --git a/apps/multiplatform/product/views/chat-list.md b/apps/multiplatform/product/views/chat-list.md index daa7907c5d..36975b646f 100644 --- a/apps/multiplatform/product/views/chat-list.md +++ b/apps/multiplatform/product/views/chat-list.md @@ -44,7 +44,7 @@ The toolbar supports two layout modes controlled by `appPrefs.oneHandUI`: |---|---| | Search icon | Magnifying glass icon at leading edge | | Text field | `SearchTextField` with placeholder "Search or paste SimpleX link" | -| Filter button | `ToggleFilterEnabledButton` (filter icon) toggles unread-only filter; shown when search text is empty | +| Filter button | `ToggleFilterEnabledButton` (filter icon) toggles unread-only filter, highlighted while the current profile has unread; shown when search text is empty | | Clear button | Appears when text is entered; `BackHandler` clears search on back | Behavior: