fix(ui): thread scaffold padding through Messages, DVMs, Search
Audit follow-up to the previous padding migration: four more `DisappearingScaffold` consumers were still using the old `HorizontalPager(contentPadding = it)` or `Modifier.padding(it)` patterns, so their feeds didn't extend behind the chrome. - Messages single-pane: `MessagesPager` no longer applies the scaffold padding to the pager's `contentPadding` (which shrinks pages); it threads it down to `ChatroomListFeedView` instead, which now accepts `scaffoldPadding` and applies it on its inner `LazyColumn` via `rememberMergedPadding(scaffoldPadding, FeedPadding)`. - Messages two-pane: drops the outer `Modifier.padding(padding) .consumeWindowInsets(padding)` on the `TwoPane` and threads the padding through `ChatroomList` → `MessagesPager` → `ChatroomListFeedView`. - `DvmContentDiscoveryScreen`: drops the wrapping `Column(Modifier .padding(paddingValues))` and threads the scaffold padding through `DvmContentDiscoveryScreen` → `ObserverContentDiscoveryResponse` → `PrepareViewContentDiscoveryModels` → `RenderNostrNIP90Content DiscoveryScreen` → `RenderFeedState`'s default `FeedLoaded`. - `SearchScreen`: drops the wrapping `Column(Modifier.padding(it).consumeWindowInsets(it))` and turns the inbox-relay warning card into a `headerContent` slot rendered as the first item of the search-results `LazyColumn`. The list now also always exists (with the early `return` moved into the lazy-list builder via `return@LazyColumn`) so the header is visible even when no search is in progress. Settings (non-scrollable) and chat detail screens (inverted layout plus a custom input field at the bottom — these need a more careful refactor to handle IME + nav inset together) intentionally left unchanged. https://claude.ai/code/session_01M3Bj24jLc9aVhMuvn55jXa
This commit is contained in:
+9
-3
@@ -21,6 +21,7 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed
|
||||
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -30,6 +31,7 @@ import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedContentState
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
@@ -39,6 +41,7 @@ import com.vitorpamplona.amethyst.ui.feeds.FeedError
|
||||
import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
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.ChatroomHeaderCompose
|
||||
@@ -49,12 +52,13 @@ import com.vitorpamplona.amethyst.ui.theme.FeedPadding
|
||||
fun ChatroomListFeedView(
|
||||
feedContentState: FeedContentState,
|
||||
scrollStateKey: String,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
RefresheableBox(feedContentState, true) {
|
||||
SaveableFeedContentState(feedContentState, scrollStateKey) { listState ->
|
||||
CrossFadeState(feedContentState, listState, accountViewModel, nav)
|
||||
CrossFadeState(feedContentState, listState, scaffoldPadding, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,6 +67,7 @@ fun ChatroomListFeedView(
|
||||
private fun CrossFadeState(
|
||||
feedContentState: FeedContentState,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -83,7 +88,7 @@ private fun CrossFadeState(
|
||||
}
|
||||
|
||||
is FeedState.Loaded -> {
|
||||
FeedLoaded(state, listState, accountViewModel, nav)
|
||||
FeedLoaded(state, listState, scaffoldPadding, accountViewModel, nav)
|
||||
}
|
||||
|
||||
FeedState.Loading -> {
|
||||
@@ -97,13 +102,14 @@ private fun CrossFadeState(
|
||||
private fun FeedLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = FeedPadding,
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
+1
-1
@@ -127,7 +127,6 @@ fun MessagesPager(
|
||||
nav: INav,
|
||||
) {
|
||||
HorizontalPager(
|
||||
contentPadding = paddingValues,
|
||||
state = pagerState,
|
||||
userScrollEnabled = true,
|
||||
modifier =
|
||||
@@ -139,6 +138,7 @@ fun MessagesPager(
|
||||
ChatroomListFeedView(
|
||||
feedContentState = tabs[page].feedContentState,
|
||||
scrollStateKey = tabs[page].scrollStateKey,
|
||||
scaffoldPadding = paddingValues,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
+2
-1
@@ -44,6 +44,7 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
fun ChatroomList(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -75,7 +76,7 @@ fun ChatroomList(
|
||||
MessagesPager(
|
||||
pagerState,
|
||||
tabs,
|
||||
PaddingValues(0.dp),
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
|
||||
+2
-2
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.twopane
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.systemBarsPadding
|
||||
@@ -97,6 +96,7 @@ fun MessagesTwoPane(
|
||||
ChatroomList(
|
||||
knownFeedContentState,
|
||||
newFeedContentState,
|
||||
padding,
|
||||
accountViewModel,
|
||||
twoPaneNav,
|
||||
)
|
||||
@@ -134,7 +134,7 @@ fun MessagesTwoPane(
|
||||
strategy = strategy,
|
||||
displayFeatures = displayFeatures,
|
||||
foldAwareConfiguration = FoldAwareConfiguration.VerticalFoldsOnly,
|
||||
modifier = Modifier.padding(padding).consumeWindowInsets(padding).fillMaxSize(),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+35
-32
@@ -23,8 +23,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.dvms
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
@@ -97,20 +97,18 @@ fun DvmContentDiscoveryScreen(
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { paddingValues ->
|
||||
Column(Modifier.padding(paddingValues)) {
|
||||
LoadNote(baseNoteHex = appDefinitionEventId, accountViewModel = accountViewModel) { note ->
|
||||
note?.let { baseNote ->
|
||||
WatchNoteEvent(
|
||||
baseNote,
|
||||
onNoteEventFound = {
|
||||
DvmContentDiscoveryScreen(baseNote, accountViewModel, nav)
|
||||
},
|
||||
onBlank = {
|
||||
FeedEmptyWithStatus(baseNote, stringRes(R.string.dvm_looking_for_app), accountViewModel, nav)
|
||||
},
|
||||
accountViewModel,
|
||||
)
|
||||
}
|
||||
LoadNote(baseNoteHex = appDefinitionEventId, accountViewModel = accountViewModel) { note ->
|
||||
note?.let { baseNote ->
|
||||
WatchNoteEvent(
|
||||
baseNote,
|
||||
onNoteEventFound = {
|
||||
DvmContentDiscoveryScreen(baseNote, paddingValues, accountViewModel, nav)
|
||||
},
|
||||
onBlank = {
|
||||
FeedEmptyWithStatus(baseNote, stringRes(R.string.dvm_looking_for_app), accountViewModel, nav)
|
||||
},
|
||||
accountViewModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,6 +117,7 @@ fun DvmContentDiscoveryScreen(
|
||||
@Composable
|
||||
fun DvmContentDiscoveryScreen(
|
||||
appDefinition: Note,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -153,6 +152,7 @@ fun DvmContentDiscoveryScreen(
|
||||
appDefinition,
|
||||
myRequestEventID,
|
||||
onRefresh,
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@@ -169,6 +169,7 @@ fun ObserverContentDiscoveryResponse(
|
||||
appDefinition: Note,
|
||||
dvmRequestId: Note,
|
||||
onRefresh: () -> Unit,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -197,6 +198,7 @@ fun ObserverContentDiscoveryResponse(
|
||||
dvmRequestId.idHex,
|
||||
myResponse,
|
||||
onRefresh,
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@@ -249,6 +251,7 @@ fun PrepareViewContentDiscoveryModels(
|
||||
dvmRequestId: String,
|
||||
latestResponse: NIP90ContentDiscoveryResponseEvent,
|
||||
onRefresh: () -> Unit,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -262,32 +265,32 @@ fun PrepareViewContentDiscoveryModels(
|
||||
resultFeedViewModel.invalidateData()
|
||||
}
|
||||
|
||||
RenderNostrNIP90ContentDiscoveryScreen(resultFeedViewModel, onRefresh, accountViewModel, nav)
|
||||
RenderNostrNIP90ContentDiscoveryScreen(resultFeedViewModel, onRefresh, scaffoldPadding, accountViewModel, nav)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderNostrNIP90ContentDiscoveryScreen(
|
||||
resultFeedViewModel: NIP90ContentDiscoveryFeedViewModel,
|
||||
onRefresh: () -> Unit,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
Column(Modifier.fillMaxHeight()) {
|
||||
SaveableFeedState(resultFeedViewModel.feedState, null) { listState ->
|
||||
// TODO (Optional) Instead of a like reaction, do a Kind 31989 NIP89 App recommendation
|
||||
RenderFeedState(
|
||||
resultFeedViewModel,
|
||||
accountViewModel,
|
||||
listState,
|
||||
nav,
|
||||
null,
|
||||
onEmpty = {
|
||||
FeedEmpty {
|
||||
onRefresh()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
SaveableFeedState(resultFeedViewModel.feedState, null) { listState ->
|
||||
// TODO (Optional) Instead of a like reaction, do a Kind 31989 NIP89 App recommendation
|
||||
RenderFeedState(
|
||||
resultFeedViewModel,
|
||||
accountViewModel,
|
||||
listState,
|
||||
nav,
|
||||
null,
|
||||
scaffoldPadding,
|
||||
onEmpty = {
|
||||
FeedEmpty {
|
||||
onRefresh()
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-14
@@ -22,9 +22,8 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.search
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -59,6 +58,7 @@ import com.vitorpamplona.amethyst.model.nip11RelayInfo.loadRelayInfo
|
||||
import com.vitorpamplona.amethyst.service.relayClient.searchCommand.TextSearchDataSourceSubscription
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
@@ -123,13 +123,14 @@ fun SearchScreen(
|
||||
}
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(it).consumeWindowInsets(it),
|
||||
) {
|
||||
ObserveRelayListForSearchAndDisplayIfNotFound(accountViewModel, nav)
|
||||
DisplaySearchResults(searchBarViewModel, nav, accountViewModel)
|
||||
}
|
||||
) { scaffoldPadding ->
|
||||
DisplaySearchResults(
|
||||
searchBarViewModel = searchBarViewModel,
|
||||
scaffoldPadding = scaffoldPadding,
|
||||
header = { ObserveRelayListForSearchAndDisplayIfNotFound(accountViewModel, nav) },
|
||||
nav = nav,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,13 +220,12 @@ private fun SearchTextField(
|
||||
@Composable
|
||||
private fun DisplaySearchResults(
|
||||
searchBarViewModel: SearchBarViewModel,
|
||||
scaffoldPadding: PaddingValues,
|
||||
header: @Composable () -> Unit,
|
||||
nav: INav,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
if (!searchBarViewModel.isRefreshing.value) {
|
||||
return
|
||||
}
|
||||
|
||||
val isRefreshing by searchBarViewModel.isRefreshing
|
||||
val hashTags by searchBarViewModel.hashtagResults.collectAsStateWithLifecycle()
|
||||
val relays by searchBarViewModel.relayResults.collectAsStateWithLifecycle()
|
||||
val users by searchBarViewModel.searchResultsUsers.collectAsStateWithLifecycle()
|
||||
@@ -236,9 +236,13 @@ private fun DisplaySearchResults(
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
contentPadding = FeedPadding,
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
state = searchBarViewModel.listState,
|
||||
) {
|
||||
item(key = "scaffold-header") { header() }
|
||||
|
||||
if (!isRefreshing) return@LazyColumn
|
||||
|
||||
itemsIndexed(
|
||||
hashTags,
|
||||
key = { _, item -> "#$item" },
|
||||
|
||||
Reference in New Issue
Block a user