Skip to content

Commit 03a186a

Browse files
committed
feat: add TermsAccept
1 parent 7d2998a commit 03a186a

File tree

3 files changed

+122
-14
lines changed

3 files changed

+122
-14
lines changed

app/src/main/kotlin/li/songe/gkd/MainActivity.kt

+21-13
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import androidx.compose.runtime.LaunchedEffect
1919
import androidx.compose.runtime.collectAsState
2020
import androidx.compose.runtime.getValue
2121
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
22+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2223
import androidx.lifecycle.lifecycleScope
2324
import androidx.navigation.compose.rememberNavController
2425
import com.dylanc.activityresult.launcher.PickContentLauncher
@@ -47,6 +48,7 @@ import li.songe.gkd.service.updateLauncherAppId
4748
import li.songe.gkd.ui.component.BuildDialog
4849
import li.songe.gkd.ui.component.ShareDataDialog
4950
import li.songe.gkd.ui.component.SubsSheet
51+
import li.songe.gkd.ui.component.TermsAcceptDialog
5052
import li.songe.gkd.ui.component.UrlDetailDialog
5153
import li.songe.gkd.ui.theme.AppTheme
5254
import li.songe.gkd.util.EditGithubCookieDlg
@@ -64,6 +66,7 @@ import li.songe.gkd.util.openApp
6466
import li.songe.gkd.util.openUri
6567
import li.songe.gkd.util.shizukuAppId
6668
import li.songe.gkd.util.storeFlow
69+
import li.songe.gkd.util.termsAcceptedFlow
6770
import li.songe.gkd.util.toast
6871
import kotlin.reflect.KClass
6972
import kotlin.reflect.jvm.jvmName
@@ -91,6 +94,7 @@ class MainActivity : ComponentActivity() {
9194
}
9295
}
9396
setContent {
97+
val termsAccepted by termsAcceptedFlow.collectAsStateWithLifecycle()
9498
val navController = rememberNavController()
9599
CompositionLocalProvider(
96100
LocalNavController provides navController,
@@ -101,20 +105,24 @@ class MainActivity : ComponentActivity() {
101105
navController = navController,
102106
navGraph = NavGraphs.root
103107
)
104-
AccessRestrictedSettingsDlg()
105-
ShizukuErrorDialog(mainVm.shizukuErrorFlow)
106-
AuthDialog(mainVm.authReasonFlow)
107-
BuildDialog(mainVm.dialogFlow)
108-
mainVm.uploadOptions.ShowDialog()
109-
EditGithubCookieDlg(mainVm.showEditCookieDlgFlow)
110-
if (META.updateEnabled) {
111-
UpgradeDialog(mainVm.updateStatus)
108+
if (!termsAccepted) {
109+
TermsAcceptDialog()
110+
} else {
111+
AccessRestrictedSettingsDlg()
112+
ShizukuErrorDialog(mainVm.shizukuErrorFlow)
113+
AuthDialog(mainVm.authReasonFlow)
114+
BuildDialog(mainVm.dialogFlow)
115+
mainVm.uploadOptions.ShowDialog()
116+
EditGithubCookieDlg(mainVm.showEditCookieDlgFlow)
117+
if (META.updateEnabled) {
118+
UpgradeDialog(mainVm.updateStatus)
119+
}
120+
SubsSheet(mainVm, mainVm.sheetSubsIdFlow)
121+
ShareDataDialog(mainVm, mainVm.showShareDataIdsFlow)
122+
mainVm.inputSubsLinkOption.ContentDialog()
123+
mainVm.ruleGroupState.Render()
124+
UrlDetailDialog(mainVm.urlFlow)
112125
}
113-
SubsSheet(mainVm, mainVm.sheetSubsIdFlow)
114-
ShareDataDialog(mainVm, mainVm.showShareDataIdsFlow)
115-
mainVm.inputSubsLinkOption.ContentDialog()
116-
mainVm.ruleGroupState.Render()
117-
UrlDetailDialog(mainVm.urlFlow)
118126
}
119127
}
120128
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package li.songe.gkd.ui.component
2+
3+
import androidx.activity.compose.LocalActivity
4+
import androidx.compose.foundation.layout.fillMaxWidth
5+
import androidx.compose.foundation.pager.HorizontalPager
6+
import androidx.compose.foundation.pager.rememberPagerState
7+
import androidx.compose.material3.AlertDialog
8+
import androidx.compose.material3.Text
9+
import androidx.compose.material3.TextButton
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.LaunchedEffect
12+
import androidx.compose.runtime.getValue
13+
import androidx.compose.runtime.mutableIntStateOf
14+
import androidx.compose.runtime.remember
15+
import androidx.compose.runtime.saveable.rememberSaveable
16+
import androidx.compose.runtime.setValue
17+
import androidx.compose.ui.Modifier
18+
import li.songe.gkd.MainActivity
19+
import li.songe.gkd.util.termsAcceptedFlow
20+
import li.songe.gkd.util.throttle
21+
22+
23+
@Composable
24+
fun TermsAcceptDialog() {
25+
// https://support.google.com/googleplay/android-developer/answer/10144311
26+
// https://support.google.com/googleplay/android-developer/answer/10964491
27+
val context = LocalActivity.current as MainActivity
28+
val stepDataList = remember {
29+
arrayOf(
30+
"使用声明" to "GKD 不收集或分享任何用户个人数据",
31+
"关于无障碍" to "GKD 请求使用系统「无障碍 API」获取屏幕信息, 以此基于用户自定义订阅规则执行自动化操作"
32+
)
33+
}
34+
var step by rememberSaveable { mutableIntStateOf(0) }
35+
val modifier = Modifier.fillMaxWidth()
36+
37+
AlertDialog(
38+
onDismissRequest = {},
39+
title = {
40+
Text(text = stepDataList[step].first)
41+
},
42+
text = {
43+
val state = rememberPagerState(step) { stepDataList.size }
44+
LaunchedEffect(step) {
45+
if (state.currentPage != step) {
46+
state.animateScrollToPage(step)
47+
}
48+
}
49+
HorizontalPager(
50+
state = state,
51+
modifier = Modifier.fillMaxWidth(),
52+
userScrollEnabled = false,
53+
) {
54+
Text(
55+
modifier = modifier,
56+
text = stepDataList[it].second,
57+
)
58+
}
59+
},
60+
confirmButton = {
61+
TextButton(onClick = throttle {
62+
if (step < stepDataList.size - 1) {
63+
step++
64+
} else {
65+
termsAcceptedFlow.value = true
66+
}
67+
}) {
68+
Text(text = "同意")
69+
}
70+
},
71+
dismissButton = {
72+
TextButton(onClick = throttle {
73+
context.finish()
74+
}) {
75+
Text(text = "不同意")
76+
}
77+
}
78+
)
79+
}

app/src/main/kotlin/li/songe/gkd/util/Store.kt

+22-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@ private fun createLongFlow(
5252
return stateFlow
5353
}
5454

55+
private fun createBooleanFlow(
56+
key: String,
57+
default: Boolean = false,
58+
transform: (Boolean) -> Boolean = { it }
59+
): MutableStateFlow<Boolean> {
60+
val stateFlow = MutableStateFlow(transform(kv.getBoolean(key, default)))
61+
appScope.launch {
62+
stateFlow.drop(1).collect {
63+
withContext(Dispatchers.IO) { kv.encode(key, it) }
64+
}
65+
}
66+
return stateFlow
67+
}
68+
5569
@Serializable
5670
data class Store(
5771
val enableService: Boolean = true,
@@ -120,7 +134,7 @@ data class ShizukuStore(
120134

121135
val shizukuStoreFlow by lazy {
122136
createJsonFlow(
123-
key = "shizuku-store",
137+
key = "shizuku_store",
124138
default = { ShizukuStore() },
125139
transform = {
126140
if (it.versionCode != META.versionCode) {
@@ -150,6 +164,13 @@ val privacyStoreFlow by lazy {
150164
)
151165
}
152166

167+
val termsAcceptedFlow by lazy {
168+
createBooleanFlow(
169+
key = "terms_accepted",
170+
default = false
171+
)
172+
}
173+
153174
fun initStore() {
154175
storeFlow.value
155176
shizukuStoreFlow.value

0 commit comments

Comments
 (0)