11package me.bmax.apatch.ui.screen
22
3- import android.content.Context
43import androidx.activity.compose.rememberLauncherForActivityResult
54import androidx.activity.result.contract.ActivityResultContracts
65import androidx.compose.foundation.background
76import androidx.compose.foundation.layout.Arrangement
87import androidx.compose.foundation.layout.Box
9- import androidx.compose.foundation.clickable
108import androidx.compose.foundation.layout.Column
119import androidx.compose.foundation.layout.Row
1210import androidx.compose.foundation.layout.Spacer
@@ -15,6 +13,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
1513import androidx.compose.foundation.layout.height
1614import androidx.compose.foundation.layout.padding
1715import androidx.compose.foundation.layout.width
16+ import androidx.compose.foundation.layout.size
1817import androidx.compose.foundation.lazy.LazyColumn
1918import androidx.compose.foundation.lazy.items
2019import androidx.compose.foundation.rememberScrollState
@@ -31,7 +30,6 @@ import me.bmax.apatch.ui.component.WallpaperAwareDropdownMenuItem
3130import androidx.compose.material3.ExperimentalMaterial3Api
3231import androidx.compose.material3.Icon
3332import androidx.compose.material3.IconButton
34- import androidx.compose.material3.ListItem
3533import androidx.compose.material3.MaterialTheme
3634import androidx.compose.material3.OutlinedTextField
3735import androidx.compose.material3.Scaffold
@@ -41,6 +39,7 @@ import androidx.compose.material3.Text
4139import androidx.compose.material3.TextButton
4240import androidx.compose.material3.TopAppBar
4341import androidx.compose.material3.Checkbox
42+ import androidx.compose.material3.CircularProgressIndicator
4443import androidx.compose.material.icons.Icons
4544import androidx.compose.material.icons.automirrored.filled.ArrowBack
4645import androidx.compose.material.icons.filled.Delete
@@ -52,6 +51,7 @@ import androidx.compose.runtime.LaunchedEffect
5251import androidx.compose.runtime.getValue
5352import androidx.compose.runtime.mutableStateOf
5453import androidx.compose.runtime.remember
54+ import androidx.compose.runtime.rememberCoroutineScope
5555import androidx.compose.runtime.setValue
5656import androidx.compose.ui.Alignment
5757import androidx.compose.ui.Modifier
@@ -64,11 +64,13 @@ import androidx.compose.ui.unit.dp
6464import com.ramcosta.composedestinations.annotation.Destination
6565import com.ramcosta.composedestinations.annotation.RootGraph
6666import com.ramcosta.composedestinations.navigation.DestinationsNavigator
67+ import kotlinx.coroutines.Dispatchers
68+ import kotlinx.coroutines.launch
69+ import kotlinx.coroutines.withContext
6770import me.bmax.apatch.R
6871import me.bmax.apatch.ui.component.KpmAutoLoadConfig
6972import me.bmax.apatch.ui.component.KpmAutoLoadEntry
7073import me.bmax.apatch.ui.component.KpmAutoLoadManager
71- import me.bmax.apatch.util.ui.APDialogBlurBehindUtils
7274import me.bmax.apatch.util.ui.showToast
7375
7476@Destination<RootGraph >
@@ -77,16 +79,19 @@ import me.bmax.apatch.util.ui.showToast
7779fun KpmAutoLoadConfigScreen (navigator : DestinationsNavigator ) {
7880 val context = LocalContext .current
7981 var isEnabled by remember { mutableStateOf(KpmAutoLoadManager .isEnabled.value) }
80- var jsonString by remember { mutableStateOf(KpmAutoLoadManager .getConfigJson() ) }
82+ var jsonString by remember { mutableStateOf(" " ) }
8183 var showSaveDialog by remember { mutableStateOf(false ) }
8284 var isValidJson by remember { mutableStateOf(true ) }
8385 var isVisualMode by remember { mutableStateOf(true ) }
8486 var kpmEntriesList by remember { mutableStateOf(KpmAutoLoadManager .entries.value.toList()) }
8587 var showFirstTimeDialog by remember { mutableStateOf(KpmAutoLoadManager .isFirstTime(context)) }
8688 var dontShowAgain by remember { mutableStateOf(false ) }
89+ var isLoading by remember { mutableStateOf(true ) }
8790
8891 var editingEntry by remember { mutableStateOf<KpmAutoLoadEntry ?>(null ) }
8992 var showEditDialog by remember { mutableStateOf(false ) }
93+
94+ val scope = rememberCoroutineScope()
9095
9196 // 根据路径列表更新JSON字符串
9297 fun updateJsonString (entries : List <KpmAutoLoadEntry >, enabled : Boolean , onUpdate : (String ) -> Unit ) {
@@ -99,26 +104,32 @@ fun KpmAutoLoadConfigScreen(navigator: DestinationsNavigator) {
99104 contract = ActivityResultContracts .GetContent ()
100105 ) { uri ->
101106 uri?.let {
102- // 导入KPM文件到内部存储
103- val importedPath = KpmAutoLoadManager .importKpm(context, it)
104-
105- if (importedPath != null && importedPath.endsWith(" .kpm" , ignoreCase = true ) && importedPath !in kpmEntriesList.map { it.path }) {
106- kpmEntriesList = kpmEntriesList + KpmAutoLoadEntry (path = importedPath)
107- updateJsonString(kpmEntriesList, isEnabled) { newJson ->
108- jsonString = newJson
107+ scope.launch {
108+ val importedPath = withContext(Dispatchers .IO ) {
109+ KpmAutoLoadManager .importKpm(context, it)
110+ }
111+
112+ if (importedPath != null && importedPath.endsWith(" .kpm" , ignoreCase = true ) && importedPath !in kpmEntriesList.map { it.path }) {
113+ kpmEntriesList = kpmEntriesList + KpmAutoLoadEntry (path = importedPath)
114+ updateJsonString(kpmEntriesList, isEnabled) { newJson ->
115+ jsonString = newJson
116+ }
117+ showToast(context, context.getString(R .string.kpm_autoload_save_success))
118+ } else if (importedPath == null ) {
119+ showToast(context, context.getString(R .string.kpm_autoload_file_not_found))
109120 }
110- showToast(context, context.getString(R .string.kpm_autoload_save_success))
111- } else if (importedPath == null ) {
112- showToast(context, context.getString(R .string.kpm_autoload_file_not_found))
113121 }
114122 }
115123 }
116124
117125 LaunchedEffect (Unit ) {
118- val config = KpmAutoLoadManager .loadConfig(context)
119- isEnabled = config.enabled
120- jsonString = KpmAutoLoadManager .getConfigJson()
121- kpmEntriesList = config.entries
126+ withContext(Dispatchers .IO ) {
127+ val config = KpmAutoLoadManager .loadConfig(context)
128+ isEnabled = config.enabled
129+ jsonString = KpmAutoLoadManager .getConfigJson()
130+ kpmEntriesList = config.entries
131+ }
132+ isLoading = false
122133 }
123134
124135 Scaffold (
@@ -136,6 +147,16 @@ fun KpmAutoLoadConfigScreen(navigator: DestinationsNavigator) {
136147 )
137148 }
138149 ) { innerPadding ->
150+ if (isLoading) {
151+ Box (
152+ modifier = Modifier
153+ .fillMaxSize()
154+ .padding(innerPadding),
155+ contentAlignment = Alignment .Center
156+ ) {
157+ CircularProgressIndicator (modifier = Modifier .size(48 .dp))
158+ }
159+ } else {
139160 Column (
140161 modifier = Modifier
141162 .fillMaxSize()
@@ -387,6 +408,7 @@ fun KpmAutoLoadConfigScreen(navigator: DestinationsNavigator) {
387408 }
388409 }
389410 }
411+ }
390412 }
391413
392414 // 保存确认对话框
@@ -425,15 +447,19 @@ fun KpmAutoLoadConfigScreen(navigator: DestinationsNavigator) {
425447 KpmAutoLoadManager .parseConfigFromJson(jsonString)?.entries ? : emptyList()
426448 )
427449 }
428-
429- val success = KpmAutoLoadManager .saveConfig(context, config)
430- if (success) {
431- showToast(context, context.getString(R .string.kpm_autoload_save_success))
432- navigator.navigateUp()
433- } else {
434- showToast(context, context.getString(R .string.kpm_autoload_save_failed))
435- }
450+
436451 showSaveDialog = false
452+ scope.launch {
453+ val success = withContext(Dispatchers .IO ) {
454+ KpmAutoLoadManager .saveConfig(context, config)
455+ }
456+ if (success) {
457+ showToast(context, context.getString(R .string.kpm_autoload_save_success))
458+ navigator.navigateUp()
459+ } else {
460+ showToast(context, context.getString(R .string.kpm_autoload_save_failed))
461+ }
462+ }
437463 }) {
438464 Text (stringResource(android.R .string.ok))
439465 }
0 commit comments