Skip to content

Commit 9db0ac1

Browse files
Save topbar background color while switching tabs,
Blur content behind bottom bar, Fixed spacing
1 parent 0b119e5 commit 9db0ac1

File tree

31 files changed

+864
-1279
lines changed

31 files changed

+864
-1279
lines changed

data/src/commonMain/kotlin/com/mrboomdev/awery/data/settings/AwerySettings.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ object AwerySettings {
2929
val darkTheme by setting(DarkTheme.AUTO)
3030
val primaryColor by setting(-1L)
3131
val amoledTheme by setting(false)
32+
val libraryStyle by setting(LibraryStyle.TABBED)
3233
val adultContent by setting(AdultContent.HIDE)
3334
val defaultPlayerFitMode by setting(PlayerFitMode.FIT)
3435
val playerDoubleTapSeek by setting(15)
35-
val defaultMainTab by setting(MainTab.HOME)
36+
val mainDefaultTab by setting(MainTab.HOME)
37+
val libraryDefaultTab by setting(-1L)
3638
val showIds by setting(false)
3739
val username by setting("")
3840
val expandRepositoriesList by setting(true)
@@ -65,4 +67,9 @@ object AwerySettings {
6567
enum class AdultContent {
6668
SHOW, HIDE, ONLY/*, STRICT*/
6769
}
70+
71+
enum class LibraryStyle {
72+
TABBED,
73+
COLUMN
74+
}
6875
}

ui/src/androidMain/kotlin/com/mrboomdev/awery/ui/screens/main/MainScreen.android.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,7 @@ private fun TvMainScreen(viewModel: MainScreenViewModel) {
198198
state = pagerState,
199199
userScrollEnabled = false
200200
) { page ->
201-
when(page) {
202-
0 -> TvHomePage(viewModel, contentPadding)
203-
1 -> SearchPage(viewModel, contentPadding, "")
204-
2 -> NotificationsPage(contentPadding)
205-
3 -> LibraryPage(viewModel, contentPadding)
206-
}
201+
TvHomePage(viewModel, contentPadding)
207202
}
208203
}
209204
}

ui/src/commonMain/kotlin/com/mrboomdev/awery/ui/App.kt

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ import com.mrboomdev.navigation.core.sealedNavigationGraph
5353
import com.mrboomdev.navigation.jetpack.JetpackNavigation
5454
import com.mrboomdev.navigation.jetpack.JetpackNavigationHost
5555
import com.mrboomdev.navigation.jetpack.bringToTop
56+
import dev.chrisbanes.haze.HazeDefaults
57+
import dev.chrisbanes.haze.hazeEffect
58+
import dev.chrisbanes.haze.hazeSource
59+
import dev.chrisbanes.haze.rememberHazeState
5660
import io.github.vinceglb.filekit.FileKit
5761
import io.github.vinceglb.filekit.div
5862
import io.github.vinceglb.filekit.filesDir
@@ -97,11 +101,32 @@ fun App() {
97101
val wallpaperOpacity = AwerySettings.wallpaperOpacity.collectAsState().value / 100f
98102
val windowSize = currentWindowSize()
99103

104+
val topAppBarBehavior = TopAppBarDefaults.pinnedScrollBehavior()
105+
val tabContentOffsets = rememberSaveable { mutableMapOf<Int, Float>() }
100106
val coroutineScope = rememberCoroutineScope()
101107
val drawerState = rememberDrawerState(DrawerValue.Closed)
102108
val toaster = remember { Toaster(maxItems = 3) }
103109
val navigationMap = rememberNavigationMap()
104-
var currentTab by rememberSaveable { mutableStateOf(0) }
110+
111+
var currentTab by rememberSaveable {
112+
mutableStateOf(run {
113+
when {
114+
!AwerySettings.introDidWelcome.value -> Routes.Intro(IntroStep.Welcome, singleStep = false)
115+
!AwerySettings.introDidTheme.value -> Routes.Intro(IntroStep.Theme, singleStep = false)
116+
AwerySettings.username.value.isBlank() -> Routes.Intro(IntroStep.UserCreation, singleStep = false)
117+
else -> null
118+
}?.also {
119+
navigationMap[0].apply {
120+
clear()
121+
push(it)
122+
}
123+
124+
return@run 0
125+
}
126+
127+
AwerySettings.mainDefaultTab.value.ordinal
128+
})
129+
}
105130

106131
val currentNavigation = navigationMap[currentTab]
107132
val currentRoute by currentNavigation.currentDestinationFlow.collectAsState(null)
@@ -134,6 +159,17 @@ fun App() {
134159

135160
contentScale = ContentScale.Crop
136161
)
162+
163+
fun onOpenTab(index: Int, route: Routes) {
164+
tabContentOffsets[currentTab] = topAppBarBehavior.state.contentOffset
165+
topAppBarBehavior.state.contentOffset = tabContentOffsets[index] ?: 0f
166+
167+
if(index == currentTab) {
168+
currentNavigation.bringToTop(route)
169+
} else {
170+
currentTab = index
171+
}
172+
}
137173

138174
Image(
139175
modifier = Modifier
@@ -189,19 +225,13 @@ fun App() {
189225
},
190226

191227
currentTab = currentTab,
192-
onOpenTab = { index, route ->
193-
if(index == currentTab) {
194-
currentNavigation.bringToTop(route)
195-
} else {
196-
currentTab = index
197-
}
198-
}
228+
onOpenTab = ::onOpenTab
199229
)
200230
}
201231

202232
Column {
203233
val installing by ExtensionInstaller.observeInstalling().collectAsState()
204-
val topAppBarBehavior = TopAppBarDefaults.pinnedScrollBehavior()
234+
val hazeState = rememberHazeState()
205235

206236
AnimatedVisibility(installing.isNotEmpty()) {
207237
Row(
@@ -255,23 +285,24 @@ fun App() {
255285

256286
bottomBar = {
257287
AnimatedVisibility(!useRail && showNavigation) {
258-
AweryBottomBar(
259-
currentTab = currentTab,
260-
onOpenTab = { index, route ->
261-
if(index == currentTab) {
262-
currentNavigation.bringToTop(route)
263-
} else {
264-
currentTab = index
265-
}
266-
}
267-
)
288+
Box(Modifier.hazeEffect(state = hazeState, style = HazeDefaults.style(
289+
blurRadius = 4.dp,
290+
backgroundColor = MaterialTheme.colorScheme.surface
291+
))) {
292+
AweryBottomBar(
293+
currentTab = currentTab,
294+
onOpenTab = ::onOpenTab
295+
)
296+
}
268297
}
269298
}
270299
) { contentPadding ->
271-
AweryNavHost(
272-
navigation = currentNavigation,
273-
contentPadding = contentPadding
274-
)
300+
Box(Modifier.hazeSource(state = hazeState)) {
301+
AweryNavHost(
302+
navigation = currentNavigation,
303+
contentPadding = contentPadding
304+
)
305+
}
275306
}
276307
}
277308
}
@@ -496,11 +527,11 @@ private fun AweryTopBar(
496527
Row(
497528
modifier = Modifier
498529
.padding(horizontal = spacing)
499-
.clip(RoundedCornerShape(12.dp))
530+
.clip(RoundedCornerShape(48.dp))
500531
.background(MaterialTheme.colorScheme.surfaceContainerHighest.let {
501532
if(AwerySettings.amoledTheme.collectAsState().value) it.copy(alpha = .75f) else it
502533
})
503-
.border(.5.dp, Color(0x22ffffff), RoundedCornerShape(12.dp))
534+
.border(.5.dp, Color(0x22ffffff), RoundedCornerShape(48.dp))
504535
.widthIn(max = 400.dp)
505536
.fillMaxWidth()
506537
.height(48.dp)
@@ -561,7 +592,7 @@ private fun AweryTopBar(
561592
) {
562593
IconButton(
563594
modifier = Modifier
564-
.heightIn(max = 42.dp)
595+
.heightIn(max = 40.dp)
565596
.fillMaxHeight()
566597
.aspectRatio(1f)
567598
.offset(x = 10.dp),

ui/src/commonMain/kotlin/com/mrboomdev/awery/ui/Navigation.kt

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.mrboomdev.awery.ui
33
import androidx.compose.foundation.layout.PaddingValues
44
import androidx.compose.runtime.Composable
55
import com.mrboomdev.awery.data.settings.AwerySettings
6+
import com.mrboomdev.awery.data.settings.collectAsState
67
import com.mrboomdev.awery.extension.sdk.Preference
78
import com.mrboomdev.awery.extension.sdk.Video
89
import com.mrboomdev.awery.resources.*
@@ -13,7 +14,8 @@ import com.mrboomdev.awery.ui.screens.home.HomeScreen
1314
import com.mrboomdev.awery.ui.screens.home.HomeViewModel
1415
import com.mrboomdev.awery.ui.screens.intro.IntroScreen
1516
import com.mrboomdev.awery.ui.screens.intro.IntroStep
16-
import com.mrboomdev.awery.ui.screens.library.LibraryScreen
17+
import com.mrboomdev.awery.ui.screens.library.LibraryColumnScreen
18+
import com.mrboomdev.awery.ui.screens.library.LibraryTabbedScreen
1719
import com.mrboomdev.awery.ui.screens.library.LibraryViewModel
1820
import com.mrboomdev.awery.ui.screens.media.MediaScreen
1921
import com.mrboomdev.awery.ui.screens.media.MediaScreenViewModel
@@ -68,7 +70,10 @@ sealed interface Routes {
6870
fun Content(
6971
viewModel: LibraryViewModel = viewModel { LibraryViewModel() },
7072
contentPadding: PaddingValues
71-
) = LibraryScreen(viewModel, contentPadding)
73+
) = when(AwerySettings.libraryStyle.collectAsState().value) {
74+
AwerySettings.LibraryStyle.TABBED -> LibraryTabbedScreen(viewModel, contentPadding)
75+
AwerySettings.LibraryStyle.COLUMN -> LibraryColumnScreen(viewModel, contentPadding)
76+
}
7277
}
7378

7479
@Serializable
@@ -126,7 +131,7 @@ sealed interface Routes {
126131
@Serializable
127132
data class ExtensionFeed(
128133
val extensionId: String,
129-
val extensionName: String,
134+
val extensionName: String?,
130135
val feedId: String,
131136
val feedName: String
132137
): Routes {
@@ -224,25 +229,4 @@ enum class MainRoutes(
224229
);
225230

226231
fun getIcon(isActive: Boolean) = if(isActive) activeIcon else icon
227-
}
228-
229-
fun getInitialRoute(): Routes {
230-
if(!AwerySettings.introDidWelcome.value) {
231-
return Routes.Intro(IntroStep.Welcome, singleStep = false)
232-
}
233-
234-
if(!AwerySettings.introDidTheme.value) {
235-
return Routes.Intro(IntroStep.Theme, singleStep = false)
236-
}
237-
238-
if(AwerySettings.username.value.isBlank()) {
239-
return Routes.Intro(IntroStep.UserCreation, singleStep = false)
240-
}
241-
242-
return when(AwerySettings.defaultMainTab.value) {
243-
AwerySettings.MainTab.HOME -> Routes.Home
244-
AwerySettings.MainTab.SEARCH -> Routes.Search
245-
AwerySettings.MainTab.NOTIFICATIONS -> Routes.Notifications
246-
AwerySettings.MainTab.LIBRARY -> Routes.Library
247-
}
248232
}

ui/src/commonMain/kotlin/com/mrboomdev/awery/ui/components/InfoBox.kt

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
11
package com.mrboomdev.awery.ui.components
22

3-
import androidx.compose.foundation.layout.Arrangement
4-
import androidx.compose.foundation.layout.Box
5-
import androidx.compose.foundation.layout.Column
6-
import androidx.compose.foundation.layout.PaddingValues
7-
import androidx.compose.foundation.layout.Row
8-
import androidx.compose.foundation.layout.padding
9-
import androidx.compose.foundation.layout.size
3+
import androidx.compose.foundation.layout.*
104
import androidx.compose.material3.Button
115
import androidx.compose.material3.Icon
126
import androidx.compose.material3.MaterialTheme
@@ -16,10 +10,8 @@ import androidx.compose.runtime.remember
1610
import androidx.compose.ui.Alignment
1711
import androidx.compose.ui.Modifier
1812
import androidx.compose.ui.graphics.painter.Painter
19-
import androidx.compose.ui.text.font.FontWeight
2013
import androidx.compose.ui.text.style.TextAlign
2114
import androidx.compose.ui.unit.dp
22-
import com.mrboomdev.awery.resources.AweryFonts
2315
import com.mrboomdev.awery.resources.Res
2416
import com.mrboomdev.awery.resources.ic_block
2517
import com.mrboomdev.awery.ui.utils.ExceptionClassifier
@@ -93,12 +85,15 @@ fun InfoBox(
9385
}
9486

9587
Text(
96-
style = MaterialTheme.typography.headlineMedium,
88+
style = MaterialTheme.typography.headlineSmall,
89+
color = MaterialTheme.colorScheme.onBackground,
9790
textAlign = TextAlign.Center,
9891
text = title
9992
)
10093

10194
Text(
95+
style = MaterialTheme.typography.bodyLarge,
96+
color = MaterialTheme.colorScheme.onSurfaceVariant,
10297
textAlign = TextAlign.Center,
10398
text = message
10499
)

ui/src/commonMain/kotlin/com/mrboomdev/awery/ui/screens/extension/ExtensionFeedScreen.kt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import com.mrboomdev.awery.data.AgeRating
2323
import com.mrboomdev.awery.data.settings.AwerySettings
2424
import com.mrboomdev.awery.extension.loaders.Extensions
2525
import com.mrboomdev.awery.extension.loaders.Extensions.get
26+
import com.mrboomdev.awery.extension.sdk.Extension
2627
import com.mrboomdev.awery.extension.sdk.Feed
2728
import com.mrboomdev.awery.extension.sdk.Media
2829
import com.mrboomdev.awery.extension.sdk.modules.CatalogModule
@@ -33,16 +34,15 @@ import com.mrboomdev.awery.ui.Routes
3334
import com.mrboomdev.awery.ui.components.*
3435
import com.mrboomdev.awery.ui.popups.MediaActionsDialog
3536
import com.mrboomdev.awery.ui.theme.isAmoledTheme
36-
import com.mrboomdev.awery.ui.utils.add
37-
import com.mrboomdev.awery.ui.utils.classify
37+
import com.mrboomdev.awery.ui.utils.*
3838
import com.mrboomdev.awery.ui.utils.pagination.InfiniteScroll
39-
import com.mrboomdev.awery.ui.utils.singleItem
40-
import com.mrboomdev.awery.ui.utils.viewModel
4139
import com.mrboomdev.navigation.core.Navigation
4240
import com.mrboomdev.navigation.core.safePop
4341
import kotlinx.coroutines.Deferred
4442
import kotlinx.coroutines.Dispatchers
4543
import kotlinx.coroutines.async
44+
import kotlinx.coroutines.flow.MutableStateFlow
45+
import kotlinx.coroutines.flow.asStateFlow
4646
import kotlinx.coroutines.withContext
4747
import org.jetbrains.compose.resources.painterResource
4848

@@ -76,7 +76,7 @@ fun ExtensionFeedScreen(
7676
.fillMaxSize()
7777
.nestedScroll(topBarBehavior.nestedScrollConnection),
7878

79-
contentWindowInsets = WindowInsets.safeDrawing,
79+
contentWindowInsets = contentPadding.asWindowInsets(),
8080
containerColor = Color.Transparent,
8181

8282
topBar = {
@@ -105,7 +105,7 @@ fun ExtensionFeedScreen(
105105
},
106106

107107
title = {
108-
Text(destination.extensionName + " - " + destination.feedName)
108+
Text((destination.extensionName ?: viewModel.extension.collectAsState().value?.name ?: "Loading...") + " - " + destination.feedName)
109109
}
110110
)
111111
}
@@ -188,6 +188,9 @@ class ExtensionFeedScreenViewModel(
188188
private val toaster: Toaster,
189189
private val navigation: Navigation<Routes>
190190
): ViewModel() {
191+
private val _extension = MutableStateFlow<Extension?>(null)
192+
val extension = _extension.asStateFlow()
193+
191194
private val feed = Feed(destination.feedId, destination.feedName)
192195
private var module: CatalogModule? = null
193196
private var currentPage = 0
@@ -207,7 +210,9 @@ class ExtensionFeedScreenViewModel(
207210
Log.e("ExtensionFeedScreen", "Failed to load an feed!", it)
208211
}) {
209212
if(module == null) {
210-
module = Extensions[destination.extensionId]?.get<CatalogModule>() ?: run {
213+
module = Extensions[destination.extensionId]?.also {
214+
_extension.emit(it)
215+
}?.get<CatalogModule>() ?: run {
211216
toaster.toast("Extension is no longer installed!")
212217
withContext(Dispatchers.Main) { navigation.safePop() }
213218
return@asyncTryingSupervise

ui/src/commonMain/kotlin/com/mrboomdev/awery/ui/screens/extension/ExtensionScreen.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ fun ExtensionScreen(
7373
topBar = {
7474
TopAppBar(
7575
scrollBehavior = topBarBehavior,
76-
windowInsets = WindowInsets.none,
76+
windowInsets = contentPadding.exclude(bottom = true).asWindowInsets(),
7777

7878
colors = TopAppBarDefaults.topAppBarColors(
7979
containerColor = Color.Transparent,
@@ -118,7 +118,8 @@ fun ExtensionScreen(
118118
LazyColumn(
119119
modifier = Modifier.fillMaxSize(),
120120
contentPadding = scaffoldContentPadding.only(vertical = true)
121-
.plus(contentPadding.only(vertical = true)).add(bottom = 16.dp),
121+
.plus(contentPadding.only(bottom = true))
122+
.add(bottom = 16.dp),
122123
verticalArrangement = if(viewModel.feeds.isEmpty()) {
123124
Arrangement.Center
124125
} else Arrangement.Top

0 commit comments

Comments
 (0)