Skip to content

Commit 1d7078c

Browse files
authored
Merge pull request #359 from OpenHub-Store/shizuku-release-fix
2 parents d246298 + 3b13dbf commit 1d7078c

6 files changed

Lines changed: 50 additions & 8 deletions

File tree

composeApp/proguard-rules.pro

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,20 @@
167167
-keep class com.google.firebase.** { *; }
168168
-dontwarn com.google.firebase.**
169169

170+
# ── Shizuku (Silent Install) ─────────────────────────────────────────────
171+
# The UserService class name is passed to Shizuku via ComponentName — R8 must
172+
# not rename or remove it, otherwise bindUserService() silently fails.
173+
-keep class zed.rainxch.core.data.services.shizuku.ShizukuInstallerServiceImpl { *; }
174+
175+
# AIDL-generated Stub/Proxy classes for IPC between app and privileged process
176+
-keep class zed.rainxch.core.data.services.shizuku.IShizukuInstallerService { *; }
177+
-keep class zed.rainxch.core.data.services.shizuku.IShizukuInstallerService$Stub { *; }
178+
-keep class zed.rainxch.core.data.services.shizuku.IShizukuInstallerService$Stub$Proxy { *; }
179+
180+
# Shizuku library internals (binder listeners, service args, provider)
181+
-keep class rikka.shizuku.** { *; }
182+
-dontwarn rikka.shizuku.**
183+
170184
# ── Enum safety ────────────────────────────────────────────────────────────
171185
# Keep all enum values and valueOf methods (used by serialization/Room)
172186
-keepclassmembers enum * {

composeApp/src/androidMain/res/xml/filepaths.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<paths xmlns:android="http://schemas.android.com/apk/res/android">
33

4-
<external-files-path
4+
<!-- Public Downloads/GitHub Store folder (visible in file managers) -->
5+
<external-path
56
name="ghs_downloads"
7+
path="Download/GitHub Store/" />
8+
9+
<!-- Legacy app-private downloads (for migration) -->
10+
<external-files-path
11+
name="ghs_legacy_downloads"
612
path="/" />
713

814
<cache-path

core/data/src/androidMain/kotlin/zed/rainxch/core/data/services/AndroidFileLocationsProvider.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,21 @@
11
package zed.rainxch.core.data.services
22

33
import android.content.Context
4+
import android.os.Environment
45
import java.io.File
56

67
class AndroidFileLocationsProvider(
78
private val context: Context,
89
) : zed.rainxch.core.data.services.FileLocationsProvider {
910
override fun appDownloadsDir(): String {
10-
val externalFilesRoot = context.getExternalFilesDir(null)
11-
val dir = File(externalFilesRoot, "ghs_downloads")
11+
val publicDownloads = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
12+
val dir = File(publicDownloads, "GitHub Store")
1213
if (!dir.exists()) dir.mkdirs()
1314
return dir.absolutePath
1415
}
1516

1617
override fun userDownloadsDir(): String {
17-
return "" // No-op
18+
return appDownloadsDir()
1819
}
1920

2021
override fun setExecutableIfNeeded(path: String) {

feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileAction.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ sealed interface ProfileAction {
3434

3535
data object OnLoginClick : ProfileAction
3636

37+
data object OnRefreshCacheSize : ProfileAction
38+
3739
data object OnClearCacheClick : ProfileAction
3840

3941
data object OnClearDownloadsConfirm : ProfileAction

feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileRoot.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ import androidx.compose.material3.SnackbarHostState
1414
import androidx.compose.material3.Text
1515
import androidx.compose.material3.TopAppBar
1616
import androidx.compose.runtime.Composable
17+
import androidx.compose.runtime.DisposableEffect
1718
import androidx.compose.runtime.getValue
1819
import androidx.compose.runtime.remember
1920
import androidx.compose.runtime.rememberCoroutineScope
2021
import androidx.compose.ui.Modifier
2122
import androidx.compose.ui.text.font.FontWeight
2223
import androidx.compose.ui.tooling.preview.Preview
2324
import androidx.compose.ui.unit.dp
25+
import androidx.lifecycle.compose.LocalLifecycleOwner
2426
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2527
import io.github.fletchmckee.liquid.liquefiable
2628
import kotlinx.coroutines.launch
@@ -54,6 +56,20 @@ fun ProfileRoot(
5456
val snackbarState = remember { SnackbarHostState() }
5557
val coroutineScope = rememberCoroutineScope()
5658

59+
val lifecycleOwner = LocalLifecycleOwner.current
60+
DisposableEffect(lifecycleOwner) {
61+
val observer =
62+
androidx.lifecycle.LifecycleEventObserver { _, event ->
63+
if (event == androidx.lifecycle.Lifecycle.Event.ON_RESUME) {
64+
viewModel.onAction(ProfileAction.OnRefreshCacheSize)
65+
}
66+
}
67+
lifecycleOwner.lifecycle.addObserver(observer)
68+
onDispose {
69+
lifecycleOwner.lifecycle.removeObserver(observer)
70+
}
71+
}
72+
5773
ObserveAsEvents(viewModel.events) { event ->
5874
when (event) {
5975
ProfileEvent.OnLogoutSuccessful -> {

feature/profile/presentation/src/commonMain/kotlin/zed/rainxch/profile/presentation/ProfileViewModel.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,11 @@ class ProfileViewModel(
5757
loadScrollbarEnabled()
5858

5959
observeLoggedInStatus()
60-
61-
observeCacheSize()
6260
observeShizukuStatus()
6361

6462
hasLoadedInitialData = true
6563
}
64+
refreshCacheSize()
6665
}.stateIn(
6766
scope = viewModelScope,
6867
started = SharingStarted.WhileSubscribed(5_000L),
@@ -72,7 +71,7 @@ class ProfileViewModel(
7271
private val _events = Channel<ProfileEvent>()
7372
val events = _events.receiveAsFlow()
7473

75-
private fun observeCacheSize() {
74+
private fun refreshCacheSize() {
7675
viewModelScope.launch {
7776
profileRepository.observeCacheSize().collect { sizeBytes ->
7877
_state.update {
@@ -299,6 +298,10 @@ class ProfileViewModel(
299298
)
300299
}
301300

301+
ProfileAction.OnRefreshCacheSize -> {
302+
refreshCacheSize()
303+
}
304+
302305
ProfileAction.OnClearCacheClick -> {
303306
_state.update { it.copy(isClearDownloadsDialogVisible = true) }
304307
}
@@ -309,7 +312,7 @@ class ProfileViewModel(
309312
runCatching {
310313
profileRepository.clearCache()
311314
}.onSuccess {
312-
observeCacheSize()
315+
refreshCacheSize()
313316
_events.send(ProfileEvent.OnCacheCleared)
314317
}.onFailure { error ->
315318
_events.send(

0 commit comments

Comments
 (0)