Skip to content

Commit 1e47ef7

Browse files
committed
feat: backup all config (#1230)
1 parent 913d0de commit 1e47ef7

File tree

18 files changed

+299
-313
lines changed

18 files changed

+299
-313
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@
7979
android:name=".OpenFileActivity"
8080
android:exported="true"
8181
android:theme="@style/TransparentTheme">
82-
<intent-filter android:label="@string/import_data">
82+
<intent-filter android:label="@string/import_backup">
8383
<action android:name="android.intent.action.VIEW" />
8484

8585
<category android:name="android.intent.category.DEFAULT" />

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package li.songe.gkd
22

33
import android.app.Activity
44
import android.content.Intent
5+
import android.net.Uri
56
import android.os.Bundle
67
import androidx.activity.ComponentActivity
78
import androidx.activity.compose.setContent
@@ -53,6 +54,7 @@ import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
5354
import androidx.navigation3.ui.NavDisplay
5455
import com.dylanc.activityresult.launcher.PickContentLauncher
5556
import com.dylanc.activityresult.launcher.StartActivityLauncher
57+
import com.dylanc.activityresult.launcher.launchForResult
5658
import kotlinx.coroutines.Dispatchers
5759
import kotlinx.coroutines.flow.MutableStateFlow
5860
import kotlinx.coroutines.flow.drop
@@ -122,7 +124,6 @@ import li.songe.gkd.ui.WebViewPage
122124
import li.songe.gkd.ui.WebViewRoute
123125
import li.songe.gkd.ui.component.BuildDialog
124126
import li.songe.gkd.ui.component.PerfIcon
125-
import li.songe.gkd.ui.component.ShareDataDialog
126127
import li.songe.gkd.ui.component.ShareLogDlg
127128
import li.songe.gkd.ui.component.SubsSheet
128129
import li.songe.gkd.ui.component.TermsAcceptDialog
@@ -218,6 +219,17 @@ class MainActivity : ComponentActivity() {
218219
return false
219220
}
220221

222+
suspend fun pickFile(contentType: String): Uri? {
223+
val u = launcher.launchForResult(Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
224+
addCategory(Intent.CATEGORY_OPENABLE)
225+
type = contentType
226+
}).data?.data
227+
if (u == null) {
228+
toast("未选择文件")
229+
}
230+
return u
231+
}
232+
221233
override fun onCreate(savedInstanceState: Bundle?) {
222234
installSplashScreen()
223235
enableEdgeToEdge()
@@ -311,7 +323,6 @@ class MainActivity : ComponentActivity() {
311323
EditGithubCookieDlg()
312324
mainVm.updateStatus?.UpgradeDialog()
313325
SubsSheet(mainVm, mainVm.sheetSubsIdFlow)
314-
ShareDataDialog(mainVm, mainVm.showShareDataIdsFlow)
315326
mainVm.inputSubsLinkOption.ContentDialog()
316327
mainVm.ruleGroupState.Render()
317328
TextDialog(mainVm.textFlow)

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

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import li.songe.gkd.a11y.useEnabledA11yServicesFlow
2222
import li.songe.gkd.data.CrashData
2323
import li.songe.gkd.data.RawSubscription
2424
import li.songe.gkd.data.SubsItem
25-
import li.songe.gkd.data.importData
2625
import li.songe.gkd.db.DbSet
2726
import li.songe.gkd.permission.AuthReason
2827
import li.songe.gkd.permission.shizukuGrantedState
@@ -45,6 +44,7 @@ import li.songe.gkd.ui.home.BottomNavItem
4544
import li.songe.gkd.ui.home.HomeRoute
4645
import li.songe.gkd.ui.share.BaseViewModel
4746
import li.songe.gkd.util.AutomatorModeOption
47+
import li.songe.gkd.util.BackupUtils
4848
import li.songe.gkd.util.LOCAL_SUBS_ID
4949
import li.songe.gkd.util.LogUtils
5050
import li.songe.gkd.util.OnSimpleLife
@@ -127,8 +127,6 @@ class MainViewModel : BaseViewModel(), OnSimpleLife {
127127

128128
val sheetSubsIdFlow = MutableStateFlow<Long?>(null)
129129

130-
val showShareDataIdsFlow = MutableStateFlow<Set<Long>?>(null)
131-
132130
val appOrderListFlow = DbSet.actionLogDao.queryLatestUniqueAppIds().stateInit(emptyList())
133131
val appVisitOrderMapFlow = DbSet.appVisitLogDao.query().map {
134132
it.mapIndexed { i, appId -> appId to i }.toMap()
@@ -245,9 +243,7 @@ class MainViewModel : BaseViewModel(), OnSimpleLife {
245243
if (uri?.scheme == "gkd") {
246244
handleGkdUri(uri)
247245
} else if (source == OpenFileActivity::class.jvmName && uri != null) {
248-
toast("加载导入中...")
249-
tabFlow.value = BottomNavItem.SubsManage.key
250-
withContext(Dispatchers.IO) { importData(uri) }
246+
withContext(Dispatchers.IO) { BackupUtils.importBackUpData(uri) }
251247
}
252248
}
253249

app/src/main/kotlin/li/songe/gkd/data/AppConfig.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ data class AppConfig(
2323
) {
2424
@Dao
2525
interface AppConfigDao {
26+
@Query("SELECT * FROM app_config")
27+
suspend fun queryAll(): List<AppConfig>
28+
2629
@Update
2730
suspend fun update(vararg objects: AppConfig): Int
2831

app/src/main/kotlin/li/songe/gkd/data/CategoryConfig.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ data class CategoryConfig(
2525
@Dao
2626
interface CategoryConfigDao {
2727

28+
@Query("SELECT * FROM category_config")
29+
suspend fun queryAll(): List<CategoryConfig>
30+
2831
@Update
2932
suspend fun update(vararg objects: CategoryConfig): Int
3033

app/src/main/kotlin/li/songe/gkd/data/SubsConfig.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ data class SubsConfig(
5252
@Dao
5353
interface SubsConfigDao {
5454

55+
@Query("SELECT * FROM subs_config")
56+
suspend fun queryAll(): List<SubsConfig>
57+
5558
@Update
5659
suspend fun update(vararg objects: SubsConfig): Int
5760

app/src/main/kotlin/li/songe/gkd/data/TransferData.kt

Lines changed: 0 additions & 128 deletions
This file was deleted.

app/src/main/kotlin/li/songe/gkd/store/StorageExt.kt

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package li.songe.gkd.store
22

33
import kotlinx.coroutines.CoroutineScope
44
import kotlinx.coroutines.Dispatchers
5+
import kotlinx.coroutines.ExperimentalForInheritanceCoroutinesApi
56
import kotlinx.coroutines.flow.MutableStateFlow
67
import kotlinx.coroutines.flow.conflate
78
import kotlinx.coroutines.flow.debounce
@@ -41,16 +42,29 @@ private fun writeStoreText(file: File, text: String) {
4142
)
4243
}
4344

45+
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
46+
class MutableStoreStateFlow<T>(
47+
val filename: String,
48+
val decode: (String?) -> T,
49+
val encode: (T) -> String,
50+
private val stateFlow: MutableStateFlow<T>,
51+
) : MutableStateFlow<T> by stateFlow {
52+
fun encodeSelf(): String = encode(value)
53+
fun updateByDecode(text: String?) {
54+
value = decode(text)
55+
}
56+
}
57+
4458
fun <T> createTextFlow(
4559
key: String,
4660
decode: (String?) -> T,
4761
encode: (T) -> String,
4862
private: Boolean = false,
4963
scope: CoroutineScope = appScope,
5064
debounceMillis: Long = 0,
51-
): MutableStateFlow<T> {
52-
val name = if (key.contains('.')) key else "$key.txt"
53-
val file = (if (private) privateStoreFolder else storeFolder).resolve(name)
65+
): MutableStoreStateFlow<T> {
66+
val filename = if (key.contains('.')) key else "$key.txt"
67+
val file = (if (private) privateStoreFolder else storeFolder).resolve(filename)
5468
val initText = readStoreText(file)
5569
val initValue = decode(initText)
5670
val stateFlow = MutableStateFlow(initValue)
@@ -61,7 +75,12 @@ fun <T> createTextFlow(
6175
}
6276
}
6377
}
64-
return stateFlow
78+
return MutableStoreStateFlow(
79+
filename = filename,
80+
decode = decode,
81+
encode = encode,
82+
stateFlow = stateFlow,
83+
)
6584
}
6685

6786
inline fun <reified T> createAnyFlow(
@@ -71,7 +90,7 @@ inline fun <reified T> createAnyFlow(
7190
private: Boolean = false,
7291
scope: CoroutineScope = appScope,
7392
debounceMillis: Long = 0,
74-
): MutableStateFlow<T> {
93+
): MutableStoreStateFlow<T> {
7594
return createTextFlow(
7695
key = "$key.json",
7796
decode = {

app/src/main/kotlin/li/songe/gkd/store/StoreExt.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package li.songe.gkd.store
22

33
import kotlinx.coroutines.Dispatchers
4-
import kotlinx.coroutines.flow.MutableStateFlow
54
import kotlinx.coroutines.flow.update
65
import li.songe.gkd.appScope
76
import li.songe.gkd.service.ExposeService
@@ -10,30 +9,30 @@ import li.songe.gkd.util.AppListString
109
import li.songe.gkd.util.launchTry
1110
import li.songe.gkd.util.toast
1211

13-
val storeFlow: MutableStateFlow<SettingsStore> by lazy {
12+
val storeFlow by lazy {
1413
createAnyFlow(
1514
key = "store",
1615
default = { SettingsStore() }
1716
)
1817
}
1918

20-
val actionCountFlow: MutableStateFlow<Long> by lazy {
19+
val actionCountFlow by lazy {
2120
createTextFlow(
2221
key = "action_count",
2322
decode = { it?.toLongOrNull() ?: 0L },
2423
encode = { it.toString() },
2524
)
2625
}
2726

28-
val blockMatchAppListFlow: MutableStateFlow<Set<String>> by lazy {
27+
val blockMatchAppListFlow by lazy {
2928
createTextFlow(
3029
key = "block_match_app_list",
3130
decode = { it?.let(AppListString::decode) ?: AppListString.getDefaultBlockList() },
3231
encode = AppListString::encode,
3332
)
3433
}
3534

36-
val blockA11yAppListFlow: MutableStateFlow<Set<String>> by lazy {
35+
val blockA11yAppListFlow by lazy {
3736
createTextFlow(
3837
key = "block_a11y_app_list",
3938
decode = { it?.let(AppListString::decode) ?: emptySet() },
@@ -48,7 +47,7 @@ val actualBlockA11yAppList: Set<String>
4847
blockA11yAppListFlow.value
4948
}
5049

51-
val a11yScopeAppListFlow: MutableStateFlow<Set<String>> by lazy {
50+
val a11yScopeAppListFlow by lazy {
5251
createTextFlow(
5352
key = "a11y_scope_app_list",
5453
decode = { it?.let(AppListString::decode) ?: setOf("com.tencent.mm") },

0 commit comments

Comments
 (0)