Skip to content

Commit e994a3c

Browse files
committed
fix(chatlist): stop the selection top bar from overflowing
"N selected" wrapped onto 3 lines once the toolbar carried 5 action icons (pin/mute/mark-read/archive/delete), blowing out the bar's height. Two changes, discussed with trev/PeGaSuS in #motd: - The title now auto-shrinks its font (TextAutoSize.StepBased, 14-22sp) before ever wrapping, with maxLines=1 + ellipsis as the last-resort floor for pathological cases (huge selected counts on tiny screens). - Collapse the action row to the 3 most-reached-for actions inline (mark as read, mute, delete/remove) plus an overflow "more" menu (Icons.Filled.MoreVert) holding pin and archive/unarchive. Existing testTags (chatlist_selection_pin/mute/archive) now live on DropdownMenuItems instead of top-level IconButtons.
1 parent b3c3388 commit e994a3c

2 files changed

Lines changed: 63 additions & 21 deletions

File tree

app/src/main/kotlin/io/github/trevarj/motd/ui/chatlist/ChatListScreen.kt

Lines changed: 62 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ import androidx.compose.foundation.lazy.LazyColumn
4040
import androidx.compose.foundation.lazy.items
4141
import androidx.compose.foundation.lazy.rememberLazyListState
4242
import androidx.compose.foundation.shape.CircleShape
43+
import androidx.compose.foundation.text.TextAutoSize
4344
import androidx.compose.material.icons.Icons
4445
import androidx.compose.material.icons.automirrored.filled.ArrowBack
4546
import androidx.compose.material.icons.filled.Add
4647
import androidx.compose.material.icons.filled.Close
4748
import androidx.compose.material.icons.filled.ExpandMore
4849
import androidx.compose.material.icons.filled.KeyboardArrowUp
4950
import androidx.compose.material.icons.filled.Menu
51+
import androidx.compose.material.icons.filled.MoreVert
5052
import androidx.compose.material.icons.filled.PushPin
5153
import androidx.compose.material.icons.outlined.Archive
5254
import androidx.compose.material.icons.outlined.Delete
@@ -66,6 +68,8 @@ import androidx.compose.material3.Button
6668
import androidx.compose.material3.Card
6769
import androidx.compose.material3.CircularProgressIndicator
6870
import androidx.compose.material3.DrawerValue
71+
import androidx.compose.material3.DropdownMenu
72+
import androidx.compose.material3.DropdownMenuItem
6973
import androidx.compose.material3.ExperimentalMaterial3Api
7074
import androidx.compose.material3.FilterChip
7175
import androidx.compose.material3.FloatingActionButton
@@ -129,10 +133,12 @@ import androidx.compose.ui.semantics.liveRegion
129133
import androidx.compose.ui.semantics.semantics
130134
import androidx.compose.ui.semantics.stateDescription
131135
import androidx.compose.ui.text.font.FontWeight
136+
import androidx.compose.ui.text.style.TextOverflow
132137
import androidx.compose.ui.tooling.preview.Preview
133138
import androidx.compose.ui.unit.IntOffset
134139
import androidx.compose.ui.unit.Velocity
135140
import androidx.compose.ui.unit.dp
141+
import androidx.compose.ui.unit.sp
136142
import androidx.core.view.HapticFeedbackConstantsCompat
137143
import androidx.core.view.ViewCompat
138144
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
@@ -440,7 +446,17 @@ fun ChatListContent(
440446
) { mode ->
441447
when (mode) {
442448
ChatListTopBarMode.SELECTION -> {
443-
Text(pluralStringResource(R.plurals.chatlist_selected_count, lastSelectedRows.size, lastSelectedRows.size))
449+
// Never wrap: a growing action row must shrink this font instead
450+
// of pushing the count to multiple lines and blowing out the bar's
451+
// height. Ellipsis is only the last-resort floor once even the
452+
// smallest step can't fit (e.g. a huge selected count on a tiny
453+
// screen).
454+
Text(
455+
pluralStringResource(R.plurals.chatlist_selected_count, lastSelectedRows.size, lastSelectedRows.size),
456+
maxLines = 1,
457+
overflow = TextOverflow.Ellipsis,
458+
autoSize = TextAutoSize.StepBased(minFontSize = 14.sp, maxFontSize = 22.sp),
459+
)
444460
}
445461

446462
ChatListTopBarMode.INVITATIONS -> {
@@ -524,40 +540,65 @@ fun ChatListContent(
524540
// still apply to the live selection.
525541
val pinTarget = aggregateToggleTarget(lastSelectedRows) { it.pinned }
526542
val muteTarget = aggregateToggleTarget(lastSelectedRows) { it.muted }
543+
var overflowOpen by remember { mutableStateOf(false) }
544+
// Only the three most-reached-for actions stay inline; pin and
545+
// archive move behind "more" so a growing action set never
546+
// starves the title (the autoSize/ellipsis fallback above is
547+
// the last resort, not the primary fix) or forces icons to
548+
// shrink/wrap on narrower phones.
527549
IconButton(
528550
onClick = {
529-
onSetPinned(selectedRows.map(ChatListRow::bufferId), pinTarget)
530-
selectedIds = emptyList()
531-
},
532-
modifier = Modifier.testTag("chatlist_selection_pin"),
533-
) { Icon(Icons.Filled.PushPin, stringResource(if (pinTarget) R.string.chatlist_pin else R.string.chatlist_unpin)) }
534-
IconButton(
535-
onClick = {
536-
onSetMuted(selectedRows.map(ChatListRow::bufferId), muteTarget)
537-
selectedIds = emptyList()
538-
},
539-
modifier = Modifier.testTag("chatlist_selection_mute"),
540-
) { Icon(if (muteTarget) Icons.Outlined.NotificationsOff else Icons.Outlined.Notifications, stringResource(if (muteTarget) R.string.chatlist_mute else R.string.chatlist_unmute)) }
541-
IconButton(
542-
onClick = {
543-
// Explicit per-selection action: unlike mark-all, this
544-
// includes muted rows on purpose (hand-picking one is
545-
// opting it in).
546551
onMarkSelectedRead(selectedRows.map(ChatListRow::bufferId))
547552
selectedIds = emptyList()
548553
},
549554
modifier = Modifier.testTag("chatlist_selection_mark_read"),
550555
) { Icon(Icons.Outlined.DoneAll, stringResource(R.string.chatlist_mark_read)) }
551556
IconButton(
552557
onClick = {
553-
setArchivedWithReveal(selectedRows.map(ChatListRow::bufferId), !archiveMode)
558+
onSetMuted(selectedRows.map(ChatListRow::bufferId), muteTarget)
554559
selectedIds = emptyList()
555560
},
556-
modifier = Modifier.testTag("chatlist_selection_archive"),
557-
) { Icon(archiveActionIcon(archiveMode), stringResource(if (archiveMode) R.string.chatlist_unarchive else R.string.chatlist_archive)) }
561+
modifier = Modifier.testTag("chatlist_selection_mute"),
562+
) { Icon(if (muteTarget) Icons.Outlined.NotificationsOff else Icons.Outlined.Notifications, stringResource(if (muteTarget) R.string.chatlist_mute else R.string.chatlist_unmute)) }
558563
IconButton(onClick = { confirmRemoval = true }, modifier = Modifier.testTag("chatlist_selection_remove")) {
559564
Icon(Icons.Outlined.Delete, stringResource(R.string.chatlist_remove))
560565
}
566+
Box {
567+
IconButton(
568+
onClick = { overflowOpen = true },
569+
modifier = Modifier.testTag("chatlist_selection_more"),
570+
) {
571+
Icon(Icons.Filled.MoreVert, stringResource(R.string.chatlist_more_actions))
572+
}
573+
DropdownMenu(expanded = overflowOpen, onDismissRequest = { overflowOpen = false }) {
574+
DropdownMenuItem(
575+
text = { Text(stringResource(if (pinTarget) R.string.chatlist_pin else R.string.chatlist_unpin)) },
576+
leadingIcon = { Icon(Icons.Filled.PushPin, contentDescription = null) },
577+
modifier = Modifier.testTag("chatlist_selection_pin"),
578+
onClick = {
579+
onSetPinned(selectedRows.map(ChatListRow::bufferId), pinTarget)
580+
selectedIds = emptyList()
581+
overflowOpen = false
582+
},
583+
)
584+
DropdownMenuItem(
585+
text = {
586+
Text(
587+
stringResource(
588+
if (archiveMode) R.string.chatlist_unarchive else R.string.chatlist_archive,
589+
),
590+
)
591+
},
592+
leadingIcon = { Icon(archiveActionIcon(archiveMode), contentDescription = null) },
593+
modifier = Modifier.testTag("chatlist_selection_archive"),
594+
onClick = {
595+
setArchivedWithReveal(selectedRows.map(ChatListRow::bufferId), !archiveMode)
596+
selectedIds = emptyList()
597+
overflowOpen = false
598+
},
599+
)
600+
}
601+
}
561602
}
562603

563604
ChatListTopBarMode.DEFAULT, ChatListTopBarMode.SCOPED -> {

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,7 @@
11671167
<string name="chatlist_mute">Mute</string>
11681168
<string name="chatlist_unmute">Unmute</string>
11691169
<string name="chatlist_mark_read">Mark as read</string>
1170+
<string name="chatlist_more_actions">More actions</string>
11701171
<string name="chatlist_archive">Archive</string>
11711172
<string name="chatlist_unarchive">Unarchive</string>
11721173

0 commit comments

Comments
 (0)