Skip to content

Commit 533ce50

Browse files
authored
Merge pull request #343 from OpenHub-Store/togglable-liquid
2 parents 402f3cf + 6e24d9d commit 533ce50

56 files changed

Lines changed: 808 additions & 377 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

composeApp/src/androidMain/kotlin/zed/rainxch/githubstore/app/GithubStoreApp.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import zed.rainxch.core.data.services.UpdateScheduler
1717
import zed.rainxch.core.domain.model.InstallSource
1818
import zed.rainxch.core.domain.model.InstalledApp
1919
import zed.rainxch.core.domain.repository.InstalledAppsRepository
20-
import zed.rainxch.core.domain.repository.ThemesRepository
20+
import zed.rainxch.core.domain.repository.TweaksRepository
2121
import zed.rainxch.core.domain.system.PackageMonitor
2222
import zed.rainxch.githubstore.app.di.initKoin
2323

@@ -83,7 +83,7 @@ class GithubStoreApp : Application() {
8383
private fun scheduleBackgroundUpdateChecks() {
8484
appScope.launch {
8585
try {
86-
val intervalHours = get<ThemesRepository>().getUpdateCheckInterval().first()
86+
val intervalHours = get<TweaksRepository>().getUpdateCheckInterval().first()
8787
UpdateScheduler.schedule(
8888
context = this@GithubStoreApp,
8989
intervalHours = intervalHours,

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/Main.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ fun App(deepLinkUri: String? = null) {
102102

103103
AppNavigation(
104104
navController = navController,
105+
isLiquidGlassEnabled = state.isLiquidGlassEnabled,
105106
)
106107
}
107108
}

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/MainState.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ data class MainState(
1313
val isAmoledTheme: Boolean = false,
1414
val isDarkTheme: Boolean? = null,
1515
val currentFontTheme: FontTheme = FontTheme.CUSTOM,
16+
val isLiquidGlassEnabled: Boolean = true,
1617
)

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/MainViewModel.kt

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import kotlinx.coroutines.launch
1010
import zed.rainxch.core.domain.repository.AuthenticationState
1111
import zed.rainxch.core.domain.repository.InstalledAppsRepository
1212
import zed.rainxch.core.domain.repository.RateLimitRepository
13-
import zed.rainxch.core.domain.repository.ThemesRepository
13+
import zed.rainxch.core.domain.repository.TweaksRepository
1414
import zed.rainxch.core.domain.use_cases.SyncInstalledAppsUseCase
1515

1616
class MainViewModel(
17-
private val themesRepository: ThemesRepository,
17+
private val tweaksRepository: TweaksRepository,
1818
private val installedAppsRepository: InstalledAppsRepository,
1919
private val authenticationState: AuthenticationState,
2020
private val rateLimitRepository: RateLimitRepository,
@@ -37,7 +37,7 @@ class MainViewModel(
3737
}
3838

3939
viewModelScope.launch {
40-
themesRepository
40+
tweaksRepository
4141
.getThemeColor()
4242
.collect { theme ->
4343
_state.update {
@@ -46,7 +46,7 @@ class MainViewModel(
4646
}
4747
}
4848
viewModelScope.launch {
49-
themesRepository
49+
tweaksRepository
5050
.getAmoledTheme()
5151
.collect { isAmoled ->
5252
_state.update {
@@ -55,7 +55,7 @@ class MainViewModel(
5555
}
5656
}
5757
viewModelScope.launch {
58-
themesRepository
58+
tweaksRepository
5959
.getIsDarkTheme()
6060
.collect { isDarkTheme ->
6161
_state.update {
@@ -65,7 +65,7 @@ class MainViewModel(
6565
}
6666

6767
viewModelScope.launch {
68-
themesRepository
68+
tweaksRepository
6969
.getFontTheme()
7070
.collect { fontTheme ->
7171
_state.update {
@@ -74,6 +74,12 @@ class MainViewModel(
7474
}
7575
}
7676

77+
viewModelScope.launch {
78+
tweaksRepository.getLiquidGlassEnabled().collect { enabled ->
79+
_state.update { it.copy(isLiquidGlassEnabled = enabled) }
80+
}
81+
}
82+
7783
viewModelScope.launch {
7884
rateLimitRepository.rateLimitState.collect { rateLimitInfo ->
7985
_state.update { currentState ->

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/di/SharedModules.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ val mainModule: Module =
99
module {
1010
viewModel {
1111
MainViewModel(
12-
themesRepository = get(),
12+
tweaksRepository = get(),
1313
installedAppsRepository = get(),
1414
rateLimitRepository = get(),
1515
syncUseCase = get(),

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/AppNavigation.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ import zed.rainxch.search.presentation.SearchRoot
4040
import zed.rainxch.starred.presentation.StarredReposRoot
4141

4242
@Composable
43-
fun AppNavigation(navController: NavHostController) {
43+
fun AppNavigation(
44+
navController: NavHostController,
45+
isLiquidGlassEnabled: Boolean = true,
46+
) {
4447
val liquidState = rememberLiquidState()
4548
var bottomNavigationHeight by remember { mutableStateOf(0.dp) }
4649
val density = LocalDensity.current
@@ -294,6 +297,7 @@ fun AppNavigation(navController: NavHostController) {
294297
}
295298
},
296299
isUpdateAvailable = appsState.apps.any { it.installedApp.isUpdateAvailable },
300+
isLiquidGlassEnabled = isLiquidGlassEnabled,
297301
modifier =
298302
Modifier
299303
.align(Alignment.BottomCenter)

composeApp/src/commonMain/kotlin/zed/rainxch/githubstore/app/navigation/BottomNavigation.kt

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import androidx.compose.animation.core.animateFloatAsState
88
import androidx.compose.animation.core.spring
99
import androidx.compose.animation.core.tween
1010
import androidx.compose.foundation.background
11+
import androidx.compose.foundation.border
1112
import androidx.compose.foundation.clickable
1213
import androidx.compose.foundation.interaction.MutableInteractionSource
1314
import androidx.compose.foundation.interaction.collectIsPressedAsState
@@ -65,6 +66,7 @@ fun BottomNavigation(
6566
currentScreen: GithubStoreGraph,
6667
onNavigate: (GithubStoreGraph) -> Unit,
6768
isUpdateAvailable: Boolean,
69+
isLiquidGlassEnabled: Boolean = true,
6870
modifier: Modifier = Modifier,
6971
) {
7072
val liquidState = LocalBottomNavigationLiquid.current
@@ -129,31 +131,36 @@ fun BottomNavigation(
129131
modifier = modifier,
130132
contentAlignment = Alignment.Center,
131133
) {
134+
val useLiquid = isLiquidGlassEnabled && isLiquidFrostAvailable()
135+
132136
Box(
133137
modifier =
134138
Modifier
135139
.clip(CircleShape)
136-
.background(
137-
if (isLiquidFrostAvailable()) {
138-
MaterialTheme.colorScheme.surfaceContainerHighest.copy(
139-
alpha = if (isDarkTheme) .25f else .15f,
140-
)
141-
} else {
142-
MaterialTheme.colorScheme.surfaceContainerHighest
143-
},
144-
).then(
145-
if (isLiquidFrostAvailable()) {
146-
Modifier.liquid(liquidState) {
147-
this.shape = CircleShape
148-
this.frost = if (isDarkTheme) 12.dp else 10.dp
149-
this.curve = if (isDarkTheme) .35f else .45f
150-
this.refraction = if (isDarkTheme) .08f else .12f
151-
this.dispersion = if (isDarkTheme) .18f else .25f
152-
this.saturation = if (isDarkTheme) .40f else .55f
153-
this.contrast = if (isDarkTheme) 1.8f else 1.6f
154-
}
140+
.then(
141+
if (useLiquid) {
142+
Modifier
143+
.background(
144+
MaterialTheme.colorScheme.surfaceContainerHighest.copy(
145+
alpha = if (isDarkTheme) .25f else .15f,
146+
),
147+
).liquid(liquidState) {
148+
this.shape = CircleShape
149+
this.frost = if (isDarkTheme) 12.dp else 10.dp
150+
this.curve = if (isDarkTheme) .35f else .45f
151+
this.refraction = if (isDarkTheme) .08f else .12f
152+
this.dispersion = if (isDarkTheme) .18f else .25f
153+
this.saturation = if (isDarkTheme) .40f else .55f
154+
this.contrast = if (isDarkTheme) 1.8f else 1.6f
155+
}
155156
} else {
156157
Modifier
158+
.background(MaterialTheme.colorScheme.surfaceContainer)
159+
.border(
160+
width = 1.dp,
161+
color = MaterialTheme.colorScheme.outlineVariant,
162+
shape = CircleShape,
163+
)
157164
},
158165
).pointerInput(Unit) { },
159166
) {

core/data/src/androidMain/kotlin/zed/rainxch/core/data/di/PlatformModule.android.kt

Lines changed: 79 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ import org.koin.dsl.module
88
import zed.rainxch.core.data.local.data_store.createDataStore
99
import zed.rainxch.core.data.local.db.AppDatabase
1010
import zed.rainxch.core.data.local.db.initDatabase
11-
import zed.rainxch.core.data.services.AndroidInstallerInfoExtractor
1211
import zed.rainxch.core.data.services.AndroidDownloader
1312
import zed.rainxch.core.data.services.AndroidFileLocationsProvider
1413
import zed.rainxch.core.data.services.AndroidInstaller
14+
import zed.rainxch.core.data.services.AndroidInstallerInfoExtractor
1515
import zed.rainxch.core.data.services.AndroidLocalizationManager
1616
import zed.rainxch.core.data.services.AndroidPackageMonitor
17+
import zed.rainxch.core.data.services.AndroidUpdateScheduleManager
1718
import zed.rainxch.core.data.services.FileLocationsProvider
1819
import zed.rainxch.core.data.services.LocalizationManager
1920
import zed.rainxch.core.data.services.shizuku.AndroidInstallerStatusProvider
@@ -24,7 +25,6 @@ import zed.rainxch.core.data.utils.AndroidBrowserHelper
2425
import zed.rainxch.core.data.utils.AndroidClipboardHelper
2526
import zed.rainxch.core.data.utils.AndroidShareManager
2627
import zed.rainxch.core.domain.network.Downloader
27-
import zed.rainxch.core.data.services.AndroidUpdateScheduleManager
2828
import zed.rainxch.core.domain.system.Installer
2929
import zed.rainxch.core.domain.system.InstallerStatusProvider
3030
import zed.rainxch.core.domain.system.PackageMonitor
@@ -34,100 +34,99 @@ import zed.rainxch.core.domain.utils.BrowserHelper
3434
import zed.rainxch.core.domain.utils.ClipboardHelper
3535
import zed.rainxch.core.domain.utils.ShareManager
3636

37-
actual val corePlatformModule = module {
38-
// Core
37+
actual val corePlatformModule =
38+
module {
39+
// Core
3940

40-
single<Downloader> {
41-
AndroidDownloader(
42-
files = get(),
43-
)
44-
}
45-
46-
// AndroidInstaller — registered by class so the wrapper can inject it
47-
single {
48-
AndroidInstaller(
49-
context = get(),
50-
installerInfoExtractor = AndroidInstallerInfoExtractor(androidContext())
51-
)
52-
}
41+
single<Downloader> {
42+
AndroidDownloader(
43+
files = get(),
44+
)
45+
}
5346

54-
// ShizukuServiceManager — manages Shizuku lifecycle, permissions, service binding
55-
single {
56-
ShizukuServiceManager(
57-
context = androidContext()
58-
).also { it.initialize() }
59-
}
47+
// AndroidInstaller — registered by class so the wrapper can inject it
48+
single {
49+
AndroidInstaller(
50+
context = get(),
51+
installerInfoExtractor = AndroidInstallerInfoExtractor(androidContext()),
52+
)
53+
}
6054

61-
// Installer — the ShizukuInstallerWrapper is the public Installer singleton.
62-
// It delegates to AndroidInstaller by default, intercepting with Shizuku when enabled.
63-
single<Installer> {
64-
ShizukuInstallerWrapper(
65-
androidInstaller = get<AndroidInstaller>(),
66-
shizukuServiceManager = get(),
67-
themesRepository = get()
68-
).also { wrapper ->
69-
wrapper.observeInstallerPreference(get<CoroutineScope>())
55+
// ShizukuServiceManager — manages Shizuku lifecycle, permissions, service binding
56+
single {
57+
ShizukuServiceManager(
58+
context = androidContext(),
59+
).also { it.initialize() }
7060
}
71-
}
7261

73-
// InstallerStatusProvider — exposes Shizuku availability to the UI layer
74-
single<InstallerStatusProvider> {
75-
AndroidInstallerStatusProvider(
76-
shizukuServiceManager = get(),
77-
scope = get()
78-
)
79-
}
62+
// Installer — the ShizukuInstallerWrapper is the public Installer singleton.
63+
// It delegates to AndroidInstaller by default, intercepting with Shizuku when enabled.
64+
single<Installer> {
65+
ShizukuInstallerWrapper(
66+
androidInstaller = get<AndroidInstaller>(),
67+
shizukuServiceManager = get(),
68+
tweaksRepository = get(),
69+
).also { wrapper ->
70+
wrapper.observeInstallerPreference(get<CoroutineScope>())
71+
}
72+
}
8073

81-
single<FileLocationsProvider> {
82-
AndroidFileLocationsProvider(context = get())
83-
}
74+
// InstallerStatusProvider — exposes Shizuku availability to the UI layer
75+
single<InstallerStatusProvider> {
76+
AndroidInstallerStatusProvider(
77+
shizukuServiceManager = get(),
78+
scope = get(),
79+
)
80+
}
8481

85-
single<PackageMonitor> {
86-
AndroidPackageMonitor(androidContext())
87-
}
82+
single<FileLocationsProvider> {
83+
AndroidFileLocationsProvider(context = get())
84+
}
8885

89-
single<LocalizationManager> {
90-
AndroidLocalizationManager()
91-
}
86+
single<PackageMonitor> {
87+
AndroidPackageMonitor(androidContext())
88+
}
9289

93-
// Locals
90+
single<LocalizationManager> {
91+
AndroidLocalizationManager()
92+
}
9493

95-
single<AppDatabase> {
96-
initDatabase(androidContext())
97-
}
94+
// Locals
9895

99-
single<DataStore<Preferences>> {
100-
createDataStore(androidContext())
101-
}
96+
single<AppDatabase> {
97+
initDatabase(androidContext())
98+
}
10299

100+
single<DataStore<Preferences>> {
101+
createDataStore(androidContext())
102+
}
103103

104-
// Utils
104+
// Utils
105105

106-
single<BrowserHelper> {
107-
AndroidBrowserHelper(androidContext())
108-
}
106+
single<BrowserHelper> {
107+
AndroidBrowserHelper(androidContext())
108+
}
109109

110-
single<ClipboardHelper> {
111-
AndroidClipboardHelper(androidContext())
112-
}
110+
single<ClipboardHelper> {
111+
AndroidClipboardHelper(androidContext())
112+
}
113113

114-
single<AppLauncher> {
115-
AndroidAppLauncher(
116-
context = androidContext(),
117-
logger = get()
118-
)
119-
}
114+
single<AppLauncher> {
115+
AndroidAppLauncher(
116+
context = androidContext(),
117+
logger = get(),
118+
)
119+
}
120120

121-
single<ShareManager> {
122-
AndroidShareManager(
123-
context = androidContext()
124-
)
125-
}
121+
single<ShareManager> {
122+
AndroidShareManager(
123+
context = androidContext(),
124+
)
125+
}
126126

127-
single<UpdateScheduleManager> {
128-
AndroidUpdateScheduleManager(
129-
context = androidContext()
130-
)
127+
single<UpdateScheduleManager> {
128+
AndroidUpdateScheduleManager(
129+
context = androidContext(),
130+
)
131+
}
131132
}
132-
133-
}

0 commit comments

Comments
 (0)