refactor(ui): CompositionLocal for scaffold padding + scaffold hygiene
Follow-up polish to the disappearing-scaffold migration addressing
the review items:
1. Replace the `scaffoldPadding: PaddingValues` sprawl across ~15 feed
entry points with a single `LocalDisappearingScaffoldPadding`
CompositionLocal published by the scaffold, plus a
`rememberFeedContentPadding(inner)` helper that merges it with the
list's own baseline padding. The contract becomes implicit at the
call site ("inner LazyColumn uses rememberFeedContentPadding") and
there's no more optional parameter for a future dev to forget.
`rememberMergedPadding` stays available for manual use.
2. Fix the stale-closure bug in `DisappearingScaffold`: the NSC is
`remember`'d and keeps its captured `canScroll` lambda across
recompositions, but the lambda was reading `allowBarHide`,
`isActive`, and `accountViewModel` by closure — so later parameter
updates wouldn't be visible. Wrapped them in `rememberUpdatedState`
so the NSC's `canScroll` always sees current values.
3. Gate `ResetBarsOnResume` and the `Modifier.nestedScroll(connection)`
install on `allowBarHide`. Chat detail screens (pinned chrome) no
longer wire up a lifecycle observer or dispatch scroll events
through the NSC for bars that never move.
4. Unify header-slot naming: `SearchScreen.DisplaySearchResults` now
uses `headerContent` to match `CardFeedView.RenderCardFeed`.
5. Add `DisappearingBarNestedScrollTest` covering:
- onPostScroll never consumes
- hide/reveal deltas applied to both bars
- per-bar clamping at their independent limits
- consumed + available sum (so overscroll works)
- canScroll=false freezes the bars
- reverseLayout inverts the delta sign
- setting a smaller heightLimit clamps the current offset
- onPostFling returns Velocity.Zero to swallow phantom velocity
All 41 consumer / shared-helper files touched to remove the now-unused
`scaffoldPadding` parameter, replaced with `rememberFeedContentPadding(
FeedPadding)` at the innermost LazyColumn / LazyVerticalGrid. Behaviour
is unchanged; API surface is smaller.
https://claude.ai/code/session_01M3Bj24jLc9aVhMuvn55jXa
This commit is contained in:
@@ -21,14 +21,12 @@
|
||||
package com.vitorpamplona.amethyst.ui.feeds
|
||||
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridState
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
@@ -41,13 +39,12 @@ fun RefresheableFeedContentStateView(
|
||||
routeForLastRead: String?,
|
||||
enablePullRefresh: Boolean = true,
|
||||
scrollStateKey: String? = null,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
RefresheableBox(feedContentState, enablePullRefresh) {
|
||||
SaveableFeedContentState(feedContentState, scrollStateKey) { listState ->
|
||||
RenderFeedContentState(feedContentState, accountViewModel, listState, nav, routeForLastRead, scaffoldPadding)
|
||||
RenderFeedContentState(feedContentState, accountViewModel, listState, nav, routeForLastRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,8 +92,7 @@ fun RenderFeedContentState(
|
||||
listState: LazyListState,
|
||||
nav: INav,
|
||||
routeForLastRead: String?,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
onLoaded: @Composable (FeedState.Loaded) -> Unit = { FeedLoaded(it, listState, routeForLastRead, accountViewModel, nav, scaffoldPadding) },
|
||||
onLoaded: @Composable (FeedState.Loaded) -> Unit = { FeedLoaded(it, listState, routeForLastRead, accountViewModel, nav) },
|
||||
onEmpty: @Composable () -> Unit = { FeedEmpty(feedContentState::invalidateData) },
|
||||
onError: @Composable (String) -> Unit = { FeedError(it, feedContentState::invalidateData) },
|
||||
onLoading: @Composable () -> Unit = { LoadingFeed() },
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.feeds
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -31,10 +30,9 @@ 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.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.NoteCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
@@ -49,12 +47,11 @@ fun FeedLoaded(
|
||||
routeForLastRead: String?,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
+27
-12
@@ -26,9 +26,12 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
@@ -59,27 +62,37 @@ fun DisappearingScaffold(
|
||||
) {
|
||||
val state = rememberDisappearingBarState()
|
||||
|
||||
val canScroll = {
|
||||
allowBarHide && isActive() && accountViewModel.settings.isImmersiveScrollingActive()
|
||||
}
|
||||
// Hold the latest values in state so the NSC's captured lambda stays fresh across
|
||||
// recompositions without rebuilding the NSC itself.
|
||||
val latestIsActive by rememberUpdatedState(isActive)
|
||||
val latestAllowBarHide by rememberUpdatedState(allowBarHide)
|
||||
val latestAccountViewModel by rememberUpdatedState(accountViewModel)
|
||||
|
||||
val connection =
|
||||
remember(state, isInvertedLayout) {
|
||||
DisappearingBarNestedScroll(
|
||||
state = state,
|
||||
canScroll = canScroll,
|
||||
canScroll = {
|
||||
latestAllowBarHide &&
|
||||
latestIsActive() &&
|
||||
latestAccountViewModel.settings.isImmersiveScrollingActive()
|
||||
},
|
||||
reverseLayout = isInvertedLayout,
|
||||
)
|
||||
}
|
||||
|
||||
ResetBarsOnResume(state)
|
||||
// Only wire the lifecycle observer when the scaffold actually moves its bars.
|
||||
if (allowBarHide) ResetBarsOnResume(state)
|
||||
|
||||
SubcomposeLayout(
|
||||
modifier =
|
||||
Modifier
|
||||
.imePadding()
|
||||
.nestedScroll(connection),
|
||||
) { constraints ->
|
||||
// When bars are pinned, skip attaching the nested-scroll connection entirely.
|
||||
val rootModifier =
|
||||
if (allowBarHide) {
|
||||
Modifier.imePadding().nestedScroll(connection)
|
||||
} else {
|
||||
Modifier.imePadding()
|
||||
}
|
||||
|
||||
SubcomposeLayout(modifier = rootModifier) { constraints ->
|
||||
val layoutWidth = constraints.maxWidth
|
||||
val layoutHeight = constraints.maxHeight
|
||||
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
|
||||
@@ -127,7 +140,9 @@ fun DisappearingScaffold(
|
||||
|
||||
val contentPlaceable =
|
||||
subcompose(DisappearingSlot.Content) {
|
||||
mainContent(contentPadding)
|
||||
CompositionLocalProvider(LocalDisappearingScaffoldPadding provides contentPadding) {
|
||||
mainContent(contentPadding)
|
||||
}
|
||||
}.firstOrNull()?.measure(
|
||||
Constraints.fixed(layoutWidth, layoutHeight),
|
||||
)
|
||||
|
||||
@@ -24,14 +24,24 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.calculateEndPadding
|
||||
import androidx.compose.foundation.layout.calculateStartPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.compositionLocalOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* The padding the surrounding [DisappearingScaffold] would like its inner scrollable
|
||||
* to apply as `contentPadding`. Defaults to [PaddingValues] of 0 when no scaffold is
|
||||
* providing it, so feed composables used outside a scaffold behave as before.
|
||||
*
|
||||
* Read it via [rememberFeedContentPadding] to merge with the list's own
|
||||
* baseline padding (typically `FeedPadding`).
|
||||
*/
|
||||
val LocalDisappearingScaffoldPadding = compositionLocalOf { PaddingValues(0.dp) }
|
||||
|
||||
/**
|
||||
* Merges two [PaddingValues] component-wise, resolving start/end against the current
|
||||
* [LocalLayoutDirection]. Used to combine the scaffold's bar padding with an inner
|
||||
* list's own padding (e.g. FeedPadding) into a single `contentPadding` value for a
|
||||
* LazyColumn / LazyVerticalGrid.
|
||||
* [LocalLayoutDirection].
|
||||
*/
|
||||
@Composable
|
||||
fun rememberMergedPadding(
|
||||
@@ -48,3 +58,10 @@ fun rememberMergedPadding(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience for inner LazyColumns/LazyVerticalGrids inside a [DisappearingScaffold]:
|
||||
* merges the scaffold's reserved space with the list's own baseline padding.
|
||||
*/
|
||||
@Composable
|
||||
fun rememberFeedContentPadding(inner: PaddingValues): PaddingValues = rememberMergedPadding(LocalDisappearingScaffoldPadding.current, inner)
|
||||
|
||||
@@ -21,14 +21,12 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen
|
||||
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.lazy.grid.LazyGridState
|
||||
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
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
|
||||
@@ -50,13 +48,12 @@ fun RefresheableFeedView(
|
||||
routeForLastRead: String?,
|
||||
enablePullRefresh: Boolean = true,
|
||||
scrollStateKey: String? = null,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
RefresheableBox(viewModel, enablePullRefresh) {
|
||||
SaveableFeedState(viewModel.feedState, scrollStateKey) { listState ->
|
||||
RenderFeedState(viewModel, accountViewModel, listState, nav, routeForLastRead, scaffoldPadding)
|
||||
RenderFeedState(viewModel, accountViewModel, listState, nav, routeForLastRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,9 +101,8 @@ fun RenderFeedState(
|
||||
listState: LazyListState,
|
||||
nav: INav,
|
||||
routeForLastRead: String?,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
onLoaded: @Composable (FeedState.Loaded) -> Unit = {
|
||||
FeedLoaded(it, listState, routeForLastRead, accountViewModel, nav, scaffoldPadding)
|
||||
FeedLoaded(it, listState, routeForLastRead, accountViewModel, nav)
|
||||
},
|
||||
onEmpty: @Composable () -> Unit = { FeedEmpty { viewModel.invalidateData() } },
|
||||
onError: @Composable (String) -> Unit = { FeedError(it) { viewModel.invalidateData() } },
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen
|
||||
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
@@ -30,14 +29,13 @@ 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.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty
|
||||
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.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.UserCompose
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
@@ -50,15 +48,13 @@ fun RefreshingFeedUserFeedView(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
enablePullRefresh: Boolean = true,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
) {
|
||||
RefresheableBox(viewModel, enablePullRefresh) { UserFeedView(viewModel, scaffoldPadding, accountViewModel, nav) }
|
||||
RefresheableBox(viewModel, enablePullRefresh) { UserFeedView(viewModel, accountViewModel, nav) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UserFeedView(
|
||||
viewModel: UserFeedViewModel,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -75,7 +71,7 @@ fun UserFeedView(
|
||||
}
|
||||
|
||||
is UserFeedState.Loaded -> {
|
||||
FeedLoaded(state, scaffoldPadding, accountViewModel, nav)
|
||||
FeedLoaded(state, accountViewModel, nav)
|
||||
}
|
||||
|
||||
is UserFeedState.Loading -> {
|
||||
@@ -88,7 +84,6 @@ fun UserFeedView(
|
||||
@Composable
|
||||
private fun FeedLoaded(
|
||||
state: UserFeedState.Loaded,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -97,7 +92,7 @@ private fun FeedLoaded(
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(items, key = { _, item -> item.pubkeyHex }) { _, item ->
|
||||
|
||||
+2
-5
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.articles
|
||||
|
||||
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,10 +29,9 @@ 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.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.ChannelCardCompose
|
||||
@@ -45,14 +43,13 @@ import com.vitorpamplona.quartz.nip23LongContent.LongTextNoteEvent
|
||||
fun ArticlesFeedLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
+1
-2
@@ -77,7 +77,7 @@ fun ArticlesScreen(
|
||||
NewArticleButton(nav)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { paddingValues ->
|
||||
) {
|
||||
RefresheableBox(articlesFeedContentState, true) {
|
||||
SaveableFeedContentState(articlesFeedContentState, scrollStateKey = ScrollStateKeys.ARTICLES_SCREEN) { listState ->
|
||||
RenderFeedContentState(
|
||||
@@ -90,7 +90,6 @@ fun ArticlesScreen(
|
||||
ArticlesFeedLoaded(
|
||||
loaded = loaded,
|
||||
listState = listState,
|
||||
scaffoldPadding = paddingValues,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
-2
@@ -125,7 +125,6 @@ private fun RenderBookmarkScreen(
|
||||
RefresheableFeedView(
|
||||
privateFeedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -135,7 +134,6 @@ private fun RenderBookmarkScreen(
|
||||
RefresheableFeedView(
|
||||
publicFeedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
-2
@@ -159,7 +159,6 @@ private fun RenderOldBookmarkScreen(
|
||||
RefresheableFeedView(
|
||||
privateFeedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -169,7 +168,6 @@ private fun RenderOldBookmarkScreen(
|
||||
RefresheableFeedView(
|
||||
publicFeedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
+4
-9
@@ -21,7 +21,6 @@
|
||||
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
|
||||
@@ -31,7 +30,6 @@ 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
|
||||
@@ -41,7 +39,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.layouts.rememberFeedContentPadding
|
||||
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
|
||||
@@ -52,13 +50,12 @@ 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, scaffoldPadding, accountViewModel, nav)
|
||||
CrossFadeState(feedContentState, listState, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +64,6 @@ fun ChatroomListFeedView(
|
||||
private fun CrossFadeState(
|
||||
feedContentState: FeedContentState,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -88,7 +84,7 @@ private fun CrossFadeState(
|
||||
}
|
||||
|
||||
is FeedState.Loaded -> {
|
||||
FeedLoaded(state, listState, scaffoldPadding, accountViewModel, nav)
|
||||
FeedLoaded(state, listState, accountViewModel, nav)
|
||||
}
|
||||
|
||||
FeedState.Loading -> {
|
||||
@@ -102,14 +98,13 @@ 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 = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
-3
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.chats.rooms.feed
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
@@ -122,7 +121,6 @@ fun MessagesTabHeader(
|
||||
fun MessagesPager(
|
||||
pagerState: PagerState,
|
||||
tabs: List<MessagesTabItem>,
|
||||
paddingValues: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -138,7 +136,6 @@ fun MessagesPager(
|
||||
ChatroomListFeedView(
|
||||
feedContentState = tabs[page].feedContentState,
|
||||
scrollStateKey = tabs[page].scrollStateKey,
|
||||
scaffoldPadding = paddingValues,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
-1
@@ -98,7 +98,6 @@ fun MessagesSinglePane(
|
||||
MessagesPager(
|
||||
pagerState,
|
||||
tabs,
|
||||
it,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
|
||||
-4
@@ -21,13 +21,11 @@
|
||||
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.pager.rememberPagerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
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
|
||||
@@ -44,7 +42,6 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
fun ChatroomList(
|
||||
knownFeedContentState: FeedContentState,
|
||||
newFeedContentState: FeedContentState,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -76,7 +73,6 @@ fun ChatroomList(
|
||||
MessagesPager(
|
||||
pagerState,
|
||||
tabs,
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
|
||||
-1
@@ -96,7 +96,6 @@ fun MessagesTwoPane(
|
||||
ChatroomList(
|
||||
knownFeedContentState,
|
||||
newFeedContentState,
|
||||
padding,
|
||||
accountViewModel,
|
||||
twoPaneNav,
|
||||
)
|
||||
|
||||
-2
@@ -198,7 +198,6 @@ fun CommunityScreen(
|
||||
RefresheableFeedView(
|
||||
feedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -208,7 +207,6 @@ fun CommunityScreen(
|
||||
RefresheableFeedView(
|
||||
modFeedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
+3
-12
@@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -70,7 +69,7 @@ import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.ui.feeds.rememberForeverPagerState
|
||||
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
@@ -277,7 +276,6 @@ private fun DiscoverPages(
|
||||
routeForLastRead = tab.routeForLastRead,
|
||||
forceEventKind = tab.forceEventKind,
|
||||
listState = listState,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -289,7 +287,6 @@ private fun DiscoverPages(
|
||||
routeForLastRead = tab.routeForLastRead,
|
||||
forceEventKind = tab.forceEventKind,
|
||||
listState = listState,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -307,7 +304,6 @@ private fun RenderDiscoverFeed(
|
||||
routeForLastRead: String?,
|
||||
forceEventKind: Int?,
|
||||
listState: LazyGridState,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -334,7 +330,6 @@ private fun RenderDiscoverFeed(
|
||||
routeForLastRead,
|
||||
listState,
|
||||
forceEventKind,
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@@ -397,7 +392,6 @@ private fun RenderDiscoverFeed(
|
||||
routeForLastRead: String?,
|
||||
forceEventKind: Int?,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -424,7 +418,6 @@ private fun RenderDiscoverFeed(
|
||||
routeForLastRead,
|
||||
listState,
|
||||
forceEventKind,
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@@ -468,14 +461,13 @@ private fun DiscoverFeedLoaded(
|
||||
routeForLastRead: String?,
|
||||
listState: LazyListState,
|
||||
forceEventKind: Int?,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(items.list, key = { _, item -> item.idHex }) { _, item ->
|
||||
@@ -504,7 +496,6 @@ private fun DiscoverFeedColumnsLoaded(
|
||||
routeForLastRead: String?,
|
||||
listState: LazyGridState,
|
||||
forceEventKind: Int?,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -512,7 +503,7 @@ private fun DiscoverFeedColumnsLoaded(
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(2),
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(items.list, key = { _, item -> item.idHex }) { _, item ->
|
||||
|
||||
+4
-6
@@ -21,7 +21,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.drafts
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -54,7 +53,7 @@ import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys.DRAFTS
|
||||
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.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.topbars.ShorterTopAppBar
|
||||
import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon
|
||||
@@ -146,7 +145,7 @@ private fun RenderDraftListScreen(
|
||||
)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { scaffoldPadding ->
|
||||
) {
|
||||
RefresheableBox(feedState) {
|
||||
SaveableFeedState(feedState, DRAFTS) { listState ->
|
||||
RenderFeedContentState(
|
||||
@@ -155,7 +154,7 @@ private fun RenderDraftListScreen(
|
||||
listState = listState,
|
||||
nav = nav,
|
||||
routeForLastRead = null,
|
||||
onLoaded = { DraftFeedLoaded(it, listState, scaffoldPadding, accountViewModel, nav) },
|
||||
onLoaded = { DraftFeedLoaded(it, listState, accountViewModel, nav) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -166,14 +165,13 @@ private fun RenderDraftListScreen(
|
||||
private fun DraftFeedLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(items.list, key = { _, item -> item.idHex }) { _, item ->
|
||||
|
||||
+3
-11
@@ -23,7 +23,6 @@ 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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
@@ -96,13 +95,13 @@ fun DvmContentDiscoveryScreen(
|
||||
DvmTopBar(appDefinitionEventId, accountViewModel, nav)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { paddingValues ->
|
||||
) {
|
||||
LoadNote(baseNoteHex = appDefinitionEventId, accountViewModel = accountViewModel) { note ->
|
||||
note?.let { baseNote ->
|
||||
WatchNoteEvent(
|
||||
baseNote,
|
||||
onNoteEventFound = {
|
||||
DvmContentDiscoveryScreen(baseNote, paddingValues, accountViewModel, nav)
|
||||
DvmContentDiscoveryScreen(baseNote, accountViewModel, nav)
|
||||
},
|
||||
onBlank = {
|
||||
FeedEmptyWithStatus(baseNote, stringRes(R.string.dvm_looking_for_app), accountViewModel, nav)
|
||||
@@ -117,7 +116,6 @@ fun DvmContentDiscoveryScreen(
|
||||
@Composable
|
||||
fun DvmContentDiscoveryScreen(
|
||||
appDefinition: Note,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -152,7 +150,6 @@ fun DvmContentDiscoveryScreen(
|
||||
appDefinition,
|
||||
myRequestEventID,
|
||||
onRefresh,
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@@ -169,7 +166,6 @@ fun ObserverContentDiscoveryResponse(
|
||||
appDefinition: Note,
|
||||
dvmRequestId: Note,
|
||||
onRefresh: () -> Unit,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -198,7 +194,6 @@ fun ObserverContentDiscoveryResponse(
|
||||
dvmRequestId.idHex,
|
||||
myResponse,
|
||||
onRefresh,
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@@ -251,7 +246,6 @@ fun PrepareViewContentDiscoveryModels(
|
||||
dvmRequestId: String,
|
||||
latestResponse: NIP90ContentDiscoveryResponseEvent,
|
||||
onRefresh: () -> Unit,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -265,14 +259,13 @@ fun PrepareViewContentDiscoveryModels(
|
||||
resultFeedViewModel.invalidateData()
|
||||
}
|
||||
|
||||
RenderNostrNIP90ContentDiscoveryScreen(resultFeedViewModel, onRefresh, scaffoldPadding, accountViewModel, nav)
|
||||
RenderNostrNIP90ContentDiscoveryScreen(resultFeedViewModel, onRefresh, accountViewModel, nav)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RenderNostrNIP90ContentDiscoveryScreen(
|
||||
resultFeedViewModel: NIP90ContentDiscoveryFeedViewModel,
|
||||
onRefresh: () -> Unit,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -284,7 +277,6 @@ fun RenderNostrNIP90ContentDiscoveryScreen(
|
||||
listState,
|
||||
nav,
|
||||
null,
|
||||
scaffoldPadding,
|
||||
onEmpty = {
|
||||
FeedEmpty {
|
||||
onRefresh()
|
||||
|
||||
-3
@@ -179,7 +179,6 @@ fun FollowPackFeedScreen(
|
||||
RefresheableFeedView(
|
||||
newThreadFeedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -189,7 +188,6 @@ fun FollowPackFeedScreen(
|
||||
RefresheableFeedView(
|
||||
conversationsFeedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -198,7 +196,6 @@ fun FollowPackFeedScreen(
|
||||
2 -> {
|
||||
UserFeedView(
|
||||
membersFeedViewModel,
|
||||
it,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
|
||||
-1
@@ -103,7 +103,6 @@ fun GeoHashScreen(
|
||||
RefresheableFeedView(
|
||||
feedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
-1
@@ -108,7 +108,6 @@ fun HashtagScreen(
|
||||
RefresheableFeedView(
|
||||
feedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
+3
-10
@@ -24,7 +24,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -52,7 +51,6 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.R
|
||||
@@ -75,7 +73,7 @@ import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys
|
||||
import com.vitorpamplona.amethyst.ui.feeds.WatchLifecycleAndUpdateModel
|
||||
import com.vitorpamplona.amethyst.ui.feeds.rememberForeverPagerState
|
||||
import com.vitorpamplona.amethyst.ui.layouts.DisappearingScaffold
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
@@ -226,7 +224,6 @@ private fun HomePages(
|
||||
routeForLastRead = tabs[page].routeForLastRead,
|
||||
scrollStateKey = tabs[page].scrollStateKey,
|
||||
liveSection = tabs[page].liveSection,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -280,7 +277,6 @@ fun HomeFeeds(
|
||||
enablePullRefresh: Boolean = true,
|
||||
scrollStateKey: String? = null,
|
||||
liveSection: ChannelFeedContentState? = null,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -292,7 +288,7 @@ fun HomeFeeds(
|
||||
listState = listState,
|
||||
nav = nav,
|
||||
routeForLastRead = routeForLastRead,
|
||||
onLoaded = { FeedLoaded(it, listState, routeForLastRead, liveSection, scaffoldPadding, accountViewModel, nav) },
|
||||
onLoaded = { FeedLoaded(it, listState, routeForLastRead, liveSection, accountViewModel, nav) },
|
||||
onEmpty = { HomeFeedEmpty(feedState::invalidateData) },
|
||||
)
|
||||
}
|
||||
@@ -306,16 +302,13 @@ fun FeedLoaded(
|
||||
listState: LazyListState,
|
||||
routeForLastRead: String?,
|
||||
liveSection: ChannelFeedContentState? = null,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
val listPadding = rememberMergedPadding(scaffoldPadding, FeedPadding)
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = listPadding,
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
if (liveSection != null) {
|
||||
|
||||
+2
-4
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.longs
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -33,7 +32,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts.VideoCardCompose
|
||||
@@ -45,14 +44,13 @@ import com.vitorpamplona.quartz.nip71Video.VideoEvent
|
||||
fun LongsFeedLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
+1
-2
@@ -77,7 +77,7 @@ fun LongsScreen(
|
||||
NewLongVideoButton(accountViewModel, nav, longsFeedContentState::sendToTop)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { paddingValues ->
|
||||
) {
|
||||
RefresheableBox(longsFeedContentState, true) {
|
||||
SaveableFeedContentState(longsFeedContentState, scrollStateKey = ScrollStateKeys.LONGS_SCREEN) { listState ->
|
||||
RenderFeedContentState(
|
||||
@@ -90,7 +90,6 @@ fun LongsScreen(
|
||||
LongsFeedLoaded(
|
||||
loaded = loaded,
|
||||
listState = listState,
|
||||
scaffoldPadding = paddingValues,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
+2
-7
@@ -26,7 +26,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
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.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
@@ -52,7 +51,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.commons.ui.notifications.Card
|
||||
@@ -61,7 +59,7 @@ import com.vitorpamplona.amethyst.logTime
|
||||
import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedError
|
||||
import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.note.BadgeCompose
|
||||
import com.vitorpamplona.amethyst.ui.note.CloseIcon
|
||||
@@ -89,7 +87,6 @@ fun RenderCardFeed(
|
||||
nav: INav,
|
||||
routeForLastRead: String,
|
||||
scrollToEventId: String? = null,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
headerContent: (@Composable () -> Unit)? = null,
|
||||
) {
|
||||
val feedState by feedContent.feedContent.collectAsStateWithLifecycle()
|
||||
@@ -118,7 +115,6 @@ fun RenderCardFeed(
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
scrollToEventId = scrollToEventId,
|
||||
scaffoldPadding = scaffoldPadding,
|
||||
headerContent = headerContent,
|
||||
)
|
||||
}
|
||||
@@ -153,7 +149,6 @@ private fun FeedLoaded(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
scrollToEventId: String? = null,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
headerContent: (@Composable () -> Unit)? = null,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
@@ -179,7 +174,7 @@ private fun FeedLoaded(
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
if (headerContent != null) {
|
||||
|
||||
-1
@@ -102,7 +102,6 @@ fun NotificationScreen(
|
||||
nav = nav,
|
||||
routeForLastRead = "Notification",
|
||||
scrollToEventId = scrollToEventId,
|
||||
scaffoldPadding = it,
|
||||
headerContent = { ObserveInboxRelayListAndDisplayIfNotFound(accountViewModel, nav) },
|
||||
)
|
||||
}
|
||||
|
||||
+2
-4
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.pictures
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -33,7 +32,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
@@ -44,14 +43,13 @@ import com.vitorpamplona.quartz.nip68Picture.PictureEvent
|
||||
fun PictureFeedLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
+1
-2
@@ -77,7 +77,7 @@ fun PicturesScreen(
|
||||
NewPictureButton(accountViewModel, nav, picturesFeedContentState::sendToTop)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { paddingValues ->
|
||||
) {
|
||||
RefresheableBox(picturesFeedContentState, true) {
|
||||
SaveableFeedContentState(picturesFeedContentState, scrollStateKey = ScrollStateKeys.PICTURES_SCREEN) { listState ->
|
||||
RenderFeedContentState(
|
||||
@@ -90,7 +90,6 @@ fun PicturesScreen(
|
||||
PictureFeedLoaded(
|
||||
loaded = loaded,
|
||||
listState = listState,
|
||||
scaffoldPadding = paddingValues,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
-1
@@ -78,7 +78,6 @@ private fun RenderPinnedNotesScreen(
|
||||
RefresheableFeedView(
|
||||
pinnedNotesFeedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
-1
@@ -172,7 +172,6 @@ private fun PollsPages(
|
||||
listState = listState,
|
||||
nav = nav,
|
||||
routeForLastRead = tabs[page].routeForLastRead,
|
||||
scaffoldPadding = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-7
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.products
|
||||
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.lazy.grid.GridCells
|
||||
@@ -33,7 +32,6 @@ 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
|
||||
@@ -41,7 +39,7 @@ import com.vitorpamplona.amethyst.ui.actions.CrossfadeIfEnabled
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedEmpty
|
||||
import com.vitorpamplona.amethyst.ui.feeds.FeedError
|
||||
import com.vitorpamplona.amethyst.ui.feeds.LoadingFeed
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.ChannelCardCompose
|
||||
@@ -53,7 +51,6 @@ import com.vitorpamplona.quartz.nip99Classifieds.ClassifiedsEvent
|
||||
fun RenderProductsFeed(
|
||||
feedContentState: FeedContentState,
|
||||
gridState: LazyGridState,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -78,7 +75,6 @@ fun RenderProductsFeed(
|
||||
ProductsFeedColumnsLoaded(
|
||||
state,
|
||||
gridState,
|
||||
scaffoldPadding,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@@ -96,7 +92,6 @@ fun RenderProductsFeed(
|
||||
private fun ProductsFeedColumnsLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyGridState,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -104,7 +99,7 @@ private fun ProductsFeedColumnsLoaded(
|
||||
|
||||
LazyVerticalGrid(
|
||||
columns = GridCells.Fixed(2),
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(items.list, key = { _, item -> item.idHex }) { _, item ->
|
||||
|
||||
+1
-2
@@ -76,13 +76,12 @@ fun ProductsScreen(
|
||||
NewProductButton(accountViewModel, nav)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { paddingValues ->
|
||||
) {
|
||||
RefresheableBox(productsFeedContentState, true) {
|
||||
SaveableGridFeedContentState(productsFeedContentState, scrollStateKey = ScrollStateKeys.PRODUCTS_SCREEN) { gridState ->
|
||||
RenderProductsFeed(
|
||||
feedContentState = productsFeedContentState,
|
||||
gridState = gridState,
|
||||
scaffoldPadding = paddingValues,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
-1
@@ -106,7 +106,6 @@ fun RelayFeedScreen(
|
||||
RefresheableFeedView(
|
||||
feedViewModel,
|
||||
null,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
+6
-9
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.search
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
@@ -58,7 +57,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.layouts.rememberFeedContentPadding
|
||||
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,11 +122,10 @@ fun SearchScreen(
|
||||
}
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { scaffoldPadding ->
|
||||
) {
|
||||
DisplaySearchResults(
|
||||
searchBarViewModel = searchBarViewModel,
|
||||
scaffoldPadding = scaffoldPadding,
|
||||
header = { ObserveRelayListForSearchAndDisplayIfNotFound(accountViewModel, nav) },
|
||||
headerContent = { ObserveRelayListForSearchAndDisplayIfNotFound(accountViewModel, nav) },
|
||||
nav = nav,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
@@ -220,8 +218,7 @@ private fun SearchTextField(
|
||||
@Composable
|
||||
private fun DisplaySearchResults(
|
||||
searchBarViewModel: SearchBarViewModel,
|
||||
scaffoldPadding: PaddingValues,
|
||||
header: @Composable () -> Unit,
|
||||
headerContent: @Composable () -> Unit,
|
||||
nav: INav,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
@@ -236,10 +233,10 @@ private fun DisplaySearchResults(
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = searchBarViewModel.listState,
|
||||
) {
|
||||
item(key = "scaffold-header") { header() }
|
||||
item(key = "scaffold-header") { headerContent() }
|
||||
|
||||
if (!isRefreshing) return@LazyColumn
|
||||
|
||||
|
||||
+2
-4
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.shorts
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -33,7 +32,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.vitorpamplona.amethyst.commons.ui.feeds.FeedState
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.DividerThickness
|
||||
@@ -44,14 +43,13 @@ import com.vitorpamplona.quartz.nip71Video.VideoEvent
|
||||
fun ShortsFeedLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
+1
-2
@@ -77,7 +77,7 @@ fun ShortsScreen(
|
||||
NewShortVideoButton(accountViewModel, nav, shortsFeedContentState::sendToTop)
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { paddingValues ->
|
||||
) {
|
||||
RefresheableBox(shortsFeedContentState, true) {
|
||||
SaveableFeedContentState(shortsFeedContentState, scrollStateKey = ScrollStateKeys.SHORTS_SCREEN) { listState ->
|
||||
RenderFeedContentState(
|
||||
@@ -90,7 +90,6 @@ fun ShortsScreen(
|
||||
ShortsFeedLoaded(
|
||||
loaded = loaded,
|
||||
listState = listState,
|
||||
scaffoldPadding = paddingValues,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
+3
-5
@@ -85,7 +85,7 @@ import com.vitorpamplona.amethyst.ui.components.LoadNote
|
||||
import com.vitorpamplona.amethyst.ui.components.MyAsyncImage
|
||||
import com.vitorpamplona.amethyst.ui.components.ZoomableContentView
|
||||
import com.vitorpamplona.amethyst.ui.feeds.RefresheableBox
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberMergedPadding
|
||||
import com.vitorpamplona.amethyst.ui.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeFor
|
||||
@@ -298,7 +298,6 @@ import kotlinx.coroutines.withContext
|
||||
fun ThreadFeedView(
|
||||
noteId: String,
|
||||
viewModel: LevelFeedViewModel,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -310,7 +309,7 @@ fun ThreadFeedView(
|
||||
nav = nav,
|
||||
routeForLastRead = null,
|
||||
onLoaded = {
|
||||
RenderThreadFeed(noteId, it, viewModel.llState, viewModel, scaffoldPadding, accountViewModel, nav)
|
||||
RenderThreadFeed(noteId, it, viewModel.llState, viewModel, accountViewModel, nav)
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -322,7 +321,6 @@ fun RenderThreadFeed(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
viewModel: LevelFeedViewModel,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -359,7 +357,7 @@ fun RenderThreadFeed(
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
+1
-1
@@ -69,6 +69,6 @@ fun ThreadScreen(
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) {
|
||||
ThreadFeedView(noteId, feedViewModel, it, accountViewModel, nav)
|
||||
ThreadFeedView(noteId, feedViewModel, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-7
@@ -20,7 +20,6 @@
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.screen.loggedIn.video
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -41,7 +40,7 @@ import com.vitorpamplona.amethyst.ui.feeds.SaveableFeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys
|
||||
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.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.bottombars.AppBottomBar
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
|
||||
@@ -99,7 +98,6 @@ fun VideoScreen(
|
||||
RenderFeed(
|
||||
videoFeedContentState = videoFeedContentState,
|
||||
scrollKey = ScrollStateKeys.VIDEO_SCREEN,
|
||||
scaffoldPadding = it,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -125,7 +123,6 @@ fun WatchAccountForVideoScreen(
|
||||
private fun RenderFeed(
|
||||
videoFeedContentState: FeedContentState,
|
||||
scrollKey: String?,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
@@ -141,7 +138,6 @@ private fun RenderFeed(
|
||||
VideoFeedLoaded(
|
||||
loaded = loaded,
|
||||
listState = listState,
|
||||
scaffoldPadding = scaffoldPadding,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -155,14 +151,13 @@ private fun RenderFeed(
|
||||
fun VideoFeedLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues = PaddingValues(0.dp),
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(
|
||||
|
||||
+4
-6
@@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.webBookmarks
|
||||
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.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -81,7 +80,7 @@ import com.vitorpamplona.amethyst.ui.feeds.RenderFeedContentState
|
||||
import com.vitorpamplona.amethyst.ui.feeds.ScrollStateKeys
|
||||
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.layouts.rememberFeedContentPadding
|
||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||
import com.vitorpamplona.amethyst.ui.navigation.topbars.ShorterTopAppBar
|
||||
import com.vitorpamplona.amethyst.ui.note.ArrowBackIcon
|
||||
@@ -155,7 +154,7 @@ private fun RenderWebBookmarksScreen(
|
||||
}
|
||||
},
|
||||
accountViewModel = accountViewModel,
|
||||
) { scaffoldPadding ->
|
||||
) {
|
||||
RefresheableBox(feedState) {
|
||||
SaveableFeedState(feedState, ScrollStateKeys.WEB_BOOKMARKS) { listState ->
|
||||
RenderFeedContentState(
|
||||
@@ -164,7 +163,7 @@ private fun RenderWebBookmarksScreen(
|
||||
listState = listState,
|
||||
nav = nav,
|
||||
routeForLastRead = null,
|
||||
onLoaded = { WebBookmarksFeedLoaded(it, listState, scaffoldPadding, accountViewModel, nav) },
|
||||
onLoaded = { WebBookmarksFeedLoaded(it, listState, accountViewModel, nav) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -175,14 +174,13 @@ private fun RenderWebBookmarksScreen(
|
||||
private fun WebBookmarksFeedLoaded(
|
||||
loaded: FeedState.Loaded,
|
||||
listState: LazyListState,
|
||||
scaffoldPadding: PaddingValues,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: INav,
|
||||
) {
|
||||
val items by loaded.feed.collectAsStateWithLifecycle()
|
||||
|
||||
LazyColumn(
|
||||
contentPadding = rememberMergedPadding(scaffoldPadding, FeedPadding),
|
||||
contentPadding = rememberFeedContentPadding(FeedPadding),
|
||||
state = listState,
|
||||
) {
|
||||
itemsIndexed(items.list, key = { _, item -> item.idHex }) { _, item ->
|
||||
|
||||
+170
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2025 Vitor Pamplona
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package com.vitorpamplona.amethyst.ui.layouts
|
||||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
|
||||
import androidx.compose.ui.unit.Velocity
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class DisappearingBarNestedScrollTest {
|
||||
private fun state(
|
||||
topLimit: Float = 100f,
|
||||
bottomLimit: Float = 50f,
|
||||
) = DisappearingBarState().apply {
|
||||
topHeightLimit = topLimit
|
||||
bottomHeightLimit = bottomLimit
|
||||
}
|
||||
|
||||
private fun nsc(
|
||||
state: DisappearingBarState,
|
||||
canScroll: Boolean = true,
|
||||
reverseLayout: Boolean = false,
|
||||
) = DisappearingBarNestedScroll(
|
||||
state = state,
|
||||
canScroll = { canScroll },
|
||||
reverseLayout = reverseLayout,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `onPostScroll does not consume any delta`() {
|
||||
val state = state()
|
||||
val connection = nsc(state)
|
||||
|
||||
val consumed = connection.onPostScroll(Offset(0f, -20f), Offset(0f, 0f), NestedScrollSource.UserInput)
|
||||
|
||||
assertEquals(Offset.Zero, consumed)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `scrolling content up hides both bars by the total delta`() {
|
||||
val state = state(topLimit = 100f, bottomLimit = 50f)
|
||||
val connection = nsc(state)
|
||||
|
||||
connection.onPostScroll(Offset(0f, -30f), Offset(0f, 0f), NestedScrollSource.UserInput)
|
||||
|
||||
assertEquals(-30f, state.topHeightOffset)
|
||||
assertEquals(-30f, state.bottomHeightOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `bars clamp at their individual limits`() {
|
||||
val state = state(topLimit = 100f, bottomLimit = 50f)
|
||||
val connection = nsc(state)
|
||||
|
||||
connection.onPostScroll(Offset(0f, -200f), Offset(0f, 0f), NestedScrollSource.UserInput)
|
||||
|
||||
assertEquals(-100f, state.topHeightOffset)
|
||||
assertEquals(-50f, state.bottomHeightOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `scrolling content down reveals both bars from a hidden state`() {
|
||||
val state = state(topLimit = 100f, bottomLimit = 50f)
|
||||
state.topHeightOffset = -100f
|
||||
state.bottomHeightOffset = -50f
|
||||
val connection = nsc(state)
|
||||
|
||||
connection.onPostScroll(Offset(0f, 30f), Offset(0f, 0f), NestedScrollSource.UserInput)
|
||||
|
||||
assertEquals(-70f, state.topHeightOffset)
|
||||
assertEquals(-20f, state.bottomHeightOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `uses consumed plus available so the bars see the whole scroll attempt`() {
|
||||
val state = state()
|
||||
state.topHeightOffset = -50f
|
||||
state.bottomHeightOffset = -50f
|
||||
val connection = nsc(state)
|
||||
|
||||
// The list consumed 20px of a 40px reveal drag; 20 more was left as overscroll.
|
||||
// The bars should move by the total 40, not just one of the halves.
|
||||
connection.onPostScroll(Offset(0f, 20f), Offset(0f, 20f), NestedScrollSource.UserInput)
|
||||
|
||||
assertEquals(-10f, state.topHeightOffset)
|
||||
assertEquals(-10f, state.bottomHeightOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `canScroll returning false freezes the bars`() {
|
||||
val state = state()
|
||||
val connection = nsc(state, canScroll = false)
|
||||
|
||||
connection.onPostScroll(Offset(0f, -100f), Offset(0f, 0f), NestedScrollSource.UserInput)
|
||||
|
||||
assertEquals(0f, state.topHeightOffset)
|
||||
assertEquals(0f, state.bottomHeightOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reverseLayout inverts the delta sign`() {
|
||||
val state = state()
|
||||
val connection = nsc(state, reverseLayout = true)
|
||||
|
||||
// In reverse layout, a positive Y is a "hide" direction
|
||||
connection.onPostScroll(Offset(0f, 20f), Offset(0f, 0f), NestedScrollSource.UserInput)
|
||||
|
||||
assertEquals(-20f, state.topHeightOffset)
|
||||
assertEquals(-20f, state.bottomHeightOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `bar offsets never exceed zero when revealing`() {
|
||||
val state = state()
|
||||
// Start from a mid-hidden position
|
||||
state.topHeightOffset = -10f
|
||||
state.bottomHeightOffset = -10f
|
||||
val connection = nsc(state)
|
||||
|
||||
connection.onPostScroll(Offset(0f, 100f), Offset(0f, 0f), NestedScrollSource.UserInput)
|
||||
|
||||
assertEquals(0f, state.topHeightOffset)
|
||||
assertEquals(0f, state.bottomHeightOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setting topHeightLimit smaller than current offset clamps it in`() {
|
||||
val state = state(topLimit = 100f)
|
||||
state.topHeightOffset = -80f
|
||||
|
||||
state.topHeightLimit = 40f
|
||||
|
||||
assertEquals(-40f, state.topHeightOffset)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `onPostFling swallows all velocity so parents don't get a phantom fling`() =
|
||||
runTest {
|
||||
val state = state()
|
||||
val connection = nsc(state)
|
||||
|
||||
val remaining =
|
||||
connection.onPostFling(
|
||||
consumed = Velocity(0f, 1000f),
|
||||
available = Velocity(0f, 200f),
|
||||
)
|
||||
|
||||
assertEquals(Velocity.Zero, remaining)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user