From 2db8dc99a8d25ff557e6ca50b0a1f5a21087b3a4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 30 Apr 2026 21:15:54 +0000 Subject: [PATCH 1/2] fix(chats): drop scaffold top inset for inner feed in two-pane In MessagesSinglePane the MessagesTabHeader sits inside the DisappearingScaffold's topBar slot, so LocalDisappearingScaffoldPadding's top component already covers the bar + tabs and the inner LazyColumn's contentPadding lines the first row up flush below the tabs. In MessagesTwoPane the tabs are part of the column content rather than the scaffold's top slot. The scaffold still publishes its top-app-bar height as the top inset, so rememberFeedContentPadding inside the feed double-counts it and renders a top-app-bar-tall gap between the TabRow and the first chatroom row. Override LocalDisappearingScaffoldPadding around MessagesPager to zero the top component while preserving start/end/bottom, so the feed still clears the bottom bar. --- .../chats/rooms/twopane/ChatroomListPane.kt | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt index cadfd00a4..11fc57f07 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt @@ -21,15 +21,22 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.twopane import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.calculateEndPadding +import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel +import com.vitorpamplona.amethyst.ui.layouts.LocalDisappearingScaffoldPadding import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.ChatroomListFilterAssemblerSubscription @@ -62,6 +69,25 @@ fun ChatroomList( } } + // The outer DisappearingScaffold publishes its top-app-bar height through + // LocalDisappearingScaffoldPadding so single-pane feeds can clear the bar via + // rememberFeedContentPadding. In the two-pane layout the tabs sit inside the + // column (not the scaffold's top slot), so the inner LazyColumn must not add + // that top inset again — otherwise it shows up as a gap below the TabRow. + // Drop only the top component; keep start/end/bottom so feeds still clear + // the bottom bar. + val outerScaffoldPadding = LocalDisappearingScaffoldPadding.current + val layoutDirection = LocalLayoutDirection.current + val innerScaffoldPadding = + remember(outerScaffoldPadding, layoutDirection) { + PaddingValues( + start = outerScaffoldPadding.calculateStartPadding(layoutDirection), + top = 0.dp, + end = outerScaffoldPadding.calculateEndPadding(layoutDirection), + bottom = outerScaffoldPadding.calculateBottomPadding(), + ) + } + Column { MessagesTabHeader( pagerState, @@ -70,11 +96,13 @@ fun ChatroomList( { accountViewModel.markAllChatNotesAsRead(newFeedContentState.visibleNotes()) }, ) - MessagesPager( - pagerState, - tabs, - accountViewModel, - nav, - ) + CompositionLocalProvider(LocalDisappearingScaffoldPadding provides innerScaffoldPadding) { + MessagesPager( + pagerState, + tabs, + accountViewModel, + nav, + ) + } } } From 089261420c199930c9ee612d14d2a3d103d462d6 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 30 Apr 2026 21:32:10 +0000 Subject: [PATCH 2/2] refactor(chats): apply scaffold padding to two-pane left pane Move the workaround out of ChatroomList: use the DisappearingScaffold's padding lambda parameter (previously unused) to position the left pane below the top bar and above the bottom bar. Reset LocalDisappearingScaffoldPadding to zero only at that boundary so the inner LazyColumn inside ChatroomListFeedView doesn't double-count the bar inset and produce a gap below the TabRow. The right pane keeps systemBarsPadding because ChatroomView / PublicChatChannelView bring their own DisappearingScaffold; layering the outer padding there would stack the chat header below the outer search bar. ChatroomList stays a flat Column with no scaffold awareness. --- .../chats/rooms/twopane/ChatroomListPane.kt | 40 +++---------------- .../chats/rooms/twopane/MessagesTwoPane.kt | 36 ++++++++++++----- 2 files changed, 33 insertions(+), 43 deletions(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt index 11fc57f07..cadfd00a4 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/ChatroomListPane.kt @@ -21,22 +21,15 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.twopane import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.calculateEndPadding -import androidx.compose.foundation.layout.calculateStartPadding import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalLayoutDirection -import androidx.compose.ui.unit.dp import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel -import com.vitorpamplona.amethyst.ui.layouts.LocalDisappearingScaffoldPadding import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.datasource.ChatroomListFilterAssemblerSubscription @@ -69,25 +62,6 @@ fun ChatroomList( } } - // The outer DisappearingScaffold publishes its top-app-bar height through - // LocalDisappearingScaffoldPadding so single-pane feeds can clear the bar via - // rememberFeedContentPadding. In the two-pane layout the tabs sit inside the - // column (not the scaffold's top slot), so the inner LazyColumn must not add - // that top inset again — otherwise it shows up as a gap below the TabRow. - // Drop only the top component; keep start/end/bottom so feeds still clear - // the bottom bar. - val outerScaffoldPadding = LocalDisappearingScaffoldPadding.current - val layoutDirection = LocalLayoutDirection.current - val innerScaffoldPadding = - remember(outerScaffoldPadding, layoutDirection) { - PaddingValues( - start = outerScaffoldPadding.calculateStartPadding(layoutDirection), - top = 0.dp, - end = outerScaffoldPadding.calculateEndPadding(layoutDirection), - bottom = outerScaffoldPadding.calculateBottomPadding(), - ) - } - Column { MessagesTabHeader( pagerState, @@ -96,13 +70,11 @@ fun ChatroomList( { accountViewModel.markAllChatNotesAsRead(newFeedContentState.visibleNotes()) }, ) - CompositionLocalProvider(LocalDisappearingScaffoldPadding provides innerScaffoldPadding) { - MessagesPager( - pagerState, - tabs, - accountViewModel, - nav, - ) - } + MessagesPager( + pagerState, + tabs, + accountViewModel, + nav, + ) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/MessagesTwoPane.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/MessagesTwoPane.kt index 8ab3ff379..3a6d531a9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/MessagesTwoPane.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/rooms/twopane/MessagesTwoPane.kt @@ -21,16 +21,19 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.twopane import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp import com.google.accompanist.adaptive.FoldAwareConfiguration import com.google.accompanist.adaptive.HorizontalTwoPaneStrategy import com.google.accompanist.adaptive.TwoPane @@ -38,6 +41,7 @@ import com.google.accompanist.adaptive.calculateDisplayFeatures import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState import com.vitorpamplona.amethyst.ui.components.getActivity import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold +import com.vitorpamplona.amethyst.ui.layouts.LocalDisappearingScaffoldPadding import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.routes.Route @@ -92,20 +96,34 @@ fun MessagesTwoPane( ) { padding -> TwoPane( first = { - Box(Modifier.fillMaxSize().systemBarsPadding(), contentAlignment = Alignment.BottomEnd) { - ChatroomList( - knownFeedContentState, - newFeedContentState, - accountViewModel, - twoPaneNav, - ) + // The chatroom-list pane owns its own TabRow, so it doesn't + // need the outer scaffold's top bar to layer over it. Apply + // the scaffold padding directly and reset + // LocalDisappearingScaffoldPadding to zero so descendants + // (e.g. the LazyColumn inside ChatroomListFeedView via + // rememberFeedContentPadding) don't add the bar inset a + // second time, which would otherwise show up as a gap + // between the TabRow and the first list item. + CompositionLocalProvider(LocalDisappearingScaffoldPadding provides PaddingValues(0.dp)) { + Box(Modifier.fillMaxSize().padding(padding), contentAlignment = Alignment.BottomEnd) { + ChatroomList( + knownFeedContentState, + newFeedContentState, + accountViewModel, + twoPaneNav, + ) - Box(Modifier.padding(Size20dp), contentAlignment = Alignment.Center) { - ChannelFabColumn(nav) + Box(Modifier.padding(Size20dp), contentAlignment = Alignment.Center) { + ChannelFabColumn(nav) + } } } }, second = { + // The chat-view pane brings its own DisappearingScaffold + // (with its own chat header), so it stays edge-to-edge under + // the outer search bar via systemBarsPadding instead of the + // scaffold padding. Box(Modifier.fillMaxSize().systemBarsPadding()) { twoPaneNav.innerNav.value?.let { if (it is Route.Room) {