Skip to content

Commit cbacc51

Browse files
committed
Merge branch 'master' into ios/20250613
2 parents 4a3a746 + 46926c4 commit cbacc51

File tree

7 files changed

+1726
-1367
lines changed

7 files changed

+1726
-1367
lines changed

app/src/main/java/dev/dimension/flare/App.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import coil3.gif.GifDecoder
1010
import coil3.network.ktor3.KtorNetworkFetcherFactory
1111
import coil3.request.crossfade
1212
import coil3.svg.SvgDecoder
13+
import coil3.video.VideoFrameDecoder
1314
import dev.dimension.flare.common.AnimatedPngDecoder
1415
import dev.dimension.flare.common.AnimatedWebPDecoder
1516
import dev.dimension.flare.di.KoinHelper
@@ -41,6 +42,7 @@ class App :
4142
add(AnimatedPngDecoder.Factory())
4243
add(SvgDecoder.Factory())
4344
add(AnimatedWebPDecoder.Factory())
45+
add(VideoFrameDecoder.Factory())
4446
add(
4547
KtorNetworkFetcherFactory(
4648
httpClient = HttpClient(dev.dimension.flare.data.network.httpClientEngine),

app/src/main/java/dev/dimension/flare/ui/screen/home/HomeScreen.kt

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffo
3232
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteType
3333
import androidx.compose.material3.rememberWideNavigationRailState
3434
import androidx.compose.runtime.Composable
35+
import androidx.compose.runtime.CompositionLocalProvider
3536
import androidx.compose.runtime.DisposableEffect
3637
import androidx.compose.runtime.LaunchedEffect
3738
import androidx.compose.runtime.derivedStateOf
@@ -131,22 +132,20 @@ internal fun HomeScreen(afterInit: () -> Unit) {
131132
tabs.all.firstOrNull { getDirection(it.tabItem) == currentRoute }?.tabItem
132133
}
133134
}
134-
135135
val accountTypeState by producePresenter(key = "home_account_type_${currentTab?.account}") {
136136
accountTypePresenter(currentTab?.account ?: AccountType.Active)
137137
}
138138
val layoutType =
139139
NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(
140140
currentWindowAdaptiveInfo(),
141141
)
142-
val actualLayoutType = state.navigationState.type ?: layoutType
143142
Box {
144143
NavigationSuiteScaffold2(
145144
wideNavigationRailState = wideNavigationRailState,
146145
modifier = Modifier.fillMaxSize(),
147146
bottomBarDividerEnabled = state.navigationState.bottomBarDividerEnabled,
148147
bottomBarAutoHideEnabled = state.navigationState.bottomBarAutoHideEnabled,
149-
layoutType = actualLayoutType,
148+
layoutType = layoutType,
150149
navigationSuiteColors =
151150
NavigationSuiteDefaults.colors(
152151
navigationBarContainerColor = MaterialTheme.colorScheme.surface,
@@ -206,7 +205,7 @@ internal fun HomeScreen(afterInit: () -> Unit) {
206205
Modifier
207206
.padding(
208207
horizontal =
209-
if (actualLayoutType ==
208+
if (layoutType ==
210209
NavigationSuiteType.NavigationBar
211210
) {
212211
16.dp
@@ -259,7 +258,7 @@ internal fun HomeScreen(afterInit: () -> Unit) {
259258
}
260259
}
261260
}
262-
if (actualLayoutType == NavigationSuiteType.NavigationRail) {
261+
if (layoutType == NavigationSuiteType.NavigationRail) {
263262
AnimatedContent(
264263
wideNavigationRailState.currentValue,
265264
modifier = Modifier.padding(horizontal = 20.dp),
@@ -332,12 +331,12 @@ internal fun HomeScreen(afterInit: () -> Unit) {
332331
}
333332
},
334333
navigationSuiteItems = {
335-
tabs.primary.forEach { (tab, tabState, badgeState) ->
334+
tabs.primary.forEach { (tab, badgeState) ->
336335
item(
337336
selected = currentRoute == getDirection(tab),
338337
onClick = {
339338
if (currentRoute == getDirection(tab)) {
340-
tabState.onClick()
339+
state.scrollToTopRegistry.scrollToTop()
341340
} else {
342341
navigate(getDirection(tab))
343342
}
@@ -383,12 +382,12 @@ internal fun HomeScreen(afterInit: () -> Unit) {
383382
}
384383
},
385384
secondaryItems = {
386-
tabs.secondary.forEach { (tab, tabState) ->
385+
tabs.secondary.forEach { (tab, badgeState) ->
387386
item(
388387
selected = currentRoute == getDirection(tab),
389388
onClick = {
390389
if (currentRoute == getDirection(tab)) {
391-
tabState.onClick()
390+
state.scrollToTopRegistry.scrollToTop()
392391
} else {
393392
navigate(getDirection(tab))
394393
}
@@ -406,6 +405,20 @@ internal fun HomeScreen(afterInit: () -> Unit) {
406405
title = tab.metaData.title,
407406
)
408407
},
408+
badge =
409+
if (badgeState.isSuccess) {
410+
{
411+
badgeState.onSuccess {
412+
if (it > 0) {
413+
Badge {
414+
Text(text = it.toString())
415+
}
416+
}
417+
}
418+
}
419+
} else {
420+
null
421+
},
409422
)
410423
}
411424
},
@@ -429,15 +442,19 @@ internal fun HomeScreen(afterInit: () -> Unit) {
429442
}
430443
},
431444
) {
432-
Router(
433-
topLevelBackStack = topLevelBackStack,
434-
navigationState = state.navigationState,
435-
openDrawer = {
436-
scope.launch {
437-
wideNavigationRailState.toggle()
438-
}
439-
},
440-
)
445+
CompositionLocalProvider(
446+
LocalScrollToTopRegistry provides state.scrollToTopRegistry,
447+
) {
448+
Router(
449+
topLevelBackStack = topLevelBackStack,
450+
navigationState = state.navigationState,
451+
openDrawer = {
452+
scope.launch {
453+
wideNavigationRailState.toggle()
454+
}
455+
},
456+
)
457+
}
441458
}
442459
InAppNotificationComponent(
443460
modifier = Modifier.align(Alignment.TopCenter),
@@ -494,9 +511,14 @@ private fun presenter(settingsRepository: SettingsRepository = koinInject()) =
494511
remember {
495512
HomeTabsPresenter(settingsRepository.tabSettings)
496513
}.invoke()
514+
val scrollToTopRegistry =
515+
remember {
516+
ScrollToTopRegistry()
517+
}
497518
object {
498519
val tabs = tabs.tabs
499520
val navigationState = navigationState
521+
val scrollToTopRegistry = scrollToTopRegistry
500522
}
501523
}
502524

@@ -507,36 +529,13 @@ private fun accountTypePresenter(accountType: AccountType) =
507529
}
508530

509531
internal class NavigationState {
510-
private val state = mutableStateOf<NavigationSuiteType?>(null)
511-
private val drawerState = mutableStateOf(true)
512532
private val bottomBarAutoHideState = mutableStateOf(true)
513533
private val bottomBarDividerState = mutableStateOf(true)
514-
val type: NavigationSuiteType?
515-
get() = state.value
516-
517-
val drawerEnabled: Boolean
518-
get() = drawerState.value
519534
val bottomBarAutoHideEnabled: Boolean
520535
get() = bottomBarAutoHideState.value
521536
val bottomBarDividerEnabled: Boolean
522537
get() = bottomBarDividerState.value
523538

524-
fun hide() {
525-
state.value = NavigationSuiteType.None
526-
}
527-
528-
fun show() {
529-
state.value = null
530-
}
531-
532-
fun enableDrawer() {
533-
drawerState.value = true
534-
}
535-
536-
fun disableDrawer() {
537-
drawerState.value = false
538-
}
539-
540539
fun enableBottomBarAutoHide() {
541540
bottomBarAutoHideState.value = true
542541
}
@@ -554,14 +553,30 @@ internal class NavigationState {
554553
}
555554
}
556555

557-
private val LocalTabState =
558-
androidx.compose.runtime.staticCompositionLocalOf<HomeTabsPresenter.State.HomeTabState.HomeTabItem.TabState?> {
556+
private class ScrollToTopRegistry {
557+
private val callbacks = mutableSetOf<() -> Unit>()
558+
559+
fun registerCallback(callback: () -> Unit) {
560+
callbacks.add(callback)
561+
}
562+
563+
fun unregisterCallback(callback: () -> Unit) {
564+
callbacks.remove(callback)
565+
}
566+
567+
fun scrollToTop() {
568+
callbacks.forEach { it.invoke() }
569+
}
570+
}
571+
572+
private val LocalScrollToTopRegistry =
573+
androidx.compose.runtime.staticCompositionLocalOf<ScrollToTopRegistry?> {
559574
null
560575
}
561576

562577
@Composable
563578
internal fun RegisterTabCallback(lazyListState: LazyStaggeredGridState) {
564-
val tabState = LocalTabState.current
579+
val tabState = LocalScrollToTopRegistry.current
565580
if (tabState != null) {
566581
val scope = rememberCoroutineScope()
567582
val callback: () -> Unit =

gradle/libs.versions.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ coil3-gif = { group = "io.coil-kt.coil3", name = "coil-gif", version.ref = "coil
126126
coil3-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil3" }
127127
coil3-ktor3 = { group = "io.coil-kt.coil3", name = "coil-network-ktor3", version.ref = "coil3" }
128128
coil3-network = { group = "io.coil-kt.coil3", name = "coil-network-core", version.ref = "coil3" }
129+
coil3-video = { group = "io.coil-kt.coil3", name = "coil-video", version.ref = "coil3" }
129130
apng = { group = "com.github.penfeizhou.android.animation", name = "apng", version.ref = "apng-android" }
130131
awebp = { group = "com.github.penfeizhou.android.animation", name = "awebp", version.ref = "apng-android" }
131132
vectordrawable-animated = { group = "androidx.vectordrawable", name = "vectordrawable-animated", version = "1.2.0" }
@@ -220,7 +221,7 @@ kotlinx = ["kotlinx-datetime", "kotlinx-immutable", "kotlinx-serialization-json"
220221
koin = ["koin-core", "koin-android", "koin-compose", "koin-androidx-compose"]
221222
ktor = ["ktor-client-content-negotiation", "ktor-serialization-kotlinx-json", "ktor-client-logging", "ktor-serialization-kotlinx-xml"]
222223
coil3 = ["coil3-compose", "coil3-svg", "coil3-ktor3", "coil3-network"]
223-
coil3-extensions = ["apng", "awebp", "vectordrawable-animated", "zoomable-image", "coil3-gif"]
224+
coil3-extensions = ["apng", "awebp", "vectordrawable-animated", "zoomable-image", "coil3-gif", "coil3-video"]
224225
accompanist = ["accompanist-permissions", "accompanist-drawablepainter"]
225226
media3 = ["media3-exoplayer", "media3-ui", "media3-hls", "media3-session", "media3-ui-compose"]
226227
firebase = ["firebase-analytics-ktx", "firebase-crashlytics-ktx"]

0 commit comments

Comments
 (0)