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.
This commit is contained in:
Narasimha-sc
2026-09-05 11:39:55 +00:00
parent 76a577afb3
commit e0c380547e
4 changed files with 34 additions and 7 deletions
@@ -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
+1
View File
@@ -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)
@@ -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)
)
@@ -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: