diff --git a/app/src/main/kotlin/li/songe/gkd/ui/AdvancedPage.kt b/app/src/main/kotlin/li/songe/gkd/ui/AdvancedPage.kt index b6879d7..6c8daaa 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/AdvancedPage.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/AdvancedPage.kt @@ -15,12 +15,15 @@ import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Edit +import androidx.compose.material.icons.filled.Upload import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Card import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LocalTextStyle @@ -46,6 +49,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog import androidx.core.content.ContextCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.viewModelScope @@ -82,12 +86,16 @@ import li.songe.gkd.util.LocalLauncher import li.songe.gkd.util.LocalNavController import li.songe.gkd.util.ProfileTransitions import li.songe.gkd.util.appInfoCacheFlow +import li.songe.gkd.util.buildLogFile import li.songe.gkd.util.json import li.songe.gkd.util.launchAsFn import li.songe.gkd.util.launchTry import li.songe.gkd.util.openApp import li.songe.gkd.util.openUri +import li.songe.gkd.util.saveFileToDownloads +import li.songe.gkd.util.shareFile import li.songe.gkd.util.storeFlow +import li.songe.gkd.util.throttle import li.songe.gkd.util.toast import rikka.shizuku.Shizuku @@ -103,10 +111,62 @@ fun AdvancedPage() { val snapshotCount by vm.snapshotCountFlow.collectAsState() ShizukuErrorDialog(vm.shizukuErrorFlow) + vm.uploadOptions.ShowDialog() var showPortDlg by remember { mutableStateOf(false) } + var showShareLogDlg by remember { + mutableStateOf(false) + } + if (showShareLogDlg) { + Dialog(onDismissRequest = { showShareLogDlg = false }) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + shape = RoundedCornerShape(16.dp), + ) { + val modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + Text( + text = "分享到其他应用", modifier = Modifier + .clickable(onClick = throttle { + showShareLogDlg = false + vm.viewModelScope.launchTry(Dispatchers.IO) { + val logZipFile = buildLogFile() + context.shareFile(logZipFile, "分享日志文件") + } + }) + .then(modifier) + ) + Text( + text = "保存到下载", modifier = Modifier + .clickable(onClick = throttle { + showShareLogDlg = false + vm.viewModelScope.launchTry(Dispatchers.IO) { + val logZipFile = buildLogFile() + context.saveFileToDownloads(logZipFile) + } + }) + .then(modifier) + ) + Text( + text = "生成链接(需科学上网)", + modifier = Modifier + .clickable(onClick = throttle { + showShareLogDlg = false + vm.viewModelScope.launchTry(Dispatchers.IO) { + val logZipFile = buildLogFile() + vm.uploadOptions.startTask(logZipFile) + } + }) + .then(modifier) + ) + } + } + } val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() Scaffold( @@ -324,7 +384,7 @@ fun AdvancedPage() { } TextSwitch( - name = "隐藏快照状态栏", + name = "隐藏状态栏", desc = "当保存快照时,隐藏截图里的顶部状态栏高度区域", checked = store.hideSnapshotStatusBar ) { @@ -334,7 +394,7 @@ fun AdvancedPage() { } TextSwitch( - name = "保存快照提示", + name = "保存提示", desc = "保存快照时是否提示\"正在保存快照\"", checked = store.showSaveSnapshotToast ) { @@ -343,6 +403,37 @@ fun AdvancedPage() { ) } + Text( + text = "日志", + modifier = Modifier.titleItemPadding(), + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + ) + + TextSwitch(name = "保存日志", + desc = "保存7天日志,帮助定位BUG", + checked = store.log2FileSwitch, + onCheckedChange = { + storeFlow.value = store.copy( + log2FileSwitch = it + ) + if (!it) { + context.mainVm.viewModelScope.launchTry(Dispatchers.IO) { + val logFiles = LogUtils.getLogFiles() + if (logFiles.isNotEmpty()) { + logFiles.forEach { f -> + f.delete() + } + toast("已删除全部日志") + } + } + } + }) + + SettingItem(title = "导出日志", imageVector = Icons.Default.Upload, onClick = { + showShareLogDlg = true + }) + Text( text = "其它", modifier = Modifier.titleItemPadding(), diff --git a/app/src/main/kotlin/li/songe/gkd/ui/AdvancedVm.kt b/app/src/main/kotlin/li/songe/gkd/ui/AdvancedVm.kt index 9d90e5b..fca08d1 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/AdvancedVm.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/AdvancedVm.kt @@ -1,6 +1,5 @@ package li.songe.gkd.ui -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -8,12 +7,15 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.stateIn import li.songe.gkd.db.DbSet +import li.songe.gkd.ui.component.UploadOptions import javax.inject.Inject @HiltViewModel -class AdvancedVm @Inject constructor(stateHandle: SavedStateHandle) : ViewModel() { +class AdvancedVm @Inject constructor() : ViewModel() { val snapshotCountFlow = DbSet.snapshotDao.count().stateIn(viewModelScope, SharingStarted.Eagerly, 0) val shizukuErrorFlow = MutableStateFlow(false) + + val uploadOptions = UploadOptions(viewModelScope) } \ No newline at end of file diff --git a/app/src/main/kotlin/li/songe/gkd/ui/SnapshotPage.kt b/app/src/main/kotlin/li/songe/gkd/ui/SnapshotPage.kt index b4211b0..6885fd1 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/SnapshotPage.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/SnapshotPage.kt @@ -15,17 +15,14 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.outlined.Delete -import androidx.compose.material3.AlertDialog import androidx.compose.material3.Card import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.LocalContentColor import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable @@ -49,7 +46,6 @@ import com.blankj.utilcode.util.UriUtils import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootNavGraph import com.ramcosta.composedestinations.navigation.navigate -import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import li.songe.gkd.MainActivity @@ -63,7 +59,6 @@ import li.songe.gkd.ui.component.waitResult import li.songe.gkd.ui.destinations.ImagePreviewPageDestination import li.songe.gkd.ui.style.EmptyHeight import li.songe.gkd.util.IMPORT_BASE_URL -import li.songe.gkd.util.LoadStatus import li.songe.gkd.util.LocalNavController import li.songe.gkd.util.LocalPickContentLauncher import li.songe.gkd.util.ProfileTransitions @@ -86,7 +81,8 @@ fun SnapshotPage() { val vm = hiltViewModel() val snapshots by vm.snapshotsState.collectAsState() - val uploadStatus by vm.uploadStatusFlow.collectAsState() + + vm.uploadOptions.ShowDialog() var selectedSnapshot by remember { mutableStateOf(null) @@ -253,9 +249,9 @@ fun SnapshotPage() { } else { Text( text = "生成链接(需科学上网)", modifier = Modifier - .clickable(onClick = { + .clickable(onClick = vm.viewModelScope.launchAsFn(Dispatchers.IO) { selectedSnapshot = null - vm.uploadZip(snapshotVal) + vm.uploadOptions.startTask(SnapshotExt.getSnapshotZipFile(snapshotVal.id)) }) .then(modifier) ) @@ -323,69 +319,6 @@ fun SnapshotPage() { } } } - - when (val uploadStatusVal = uploadStatus) { - is LoadStatus.Failure -> { - AlertDialog( - title = { Text(text = "上传失败") }, - text = { - Text(text = uploadStatusVal.exception.let { - it.message ?: it.toString() - }) - }, - onDismissRequest = { vm.uploadStatusFlow.value = null }, - confirmButton = { - TextButton(onClick = { - vm.uploadStatusFlow.value = null - }) { - Text(text = "关闭") - } - }, - ) - } - - is LoadStatus.Loading -> { - AlertDialog( - title = { Text(text = "上传文件中") }, - text = { - LinearProgressIndicator( - progress = { uploadStatusVal.progress }, - ) - }, - onDismissRequest = { }, - confirmButton = { - TextButton(onClick = { - vm.uploadJob?.cancel(CancellationException("终止上传")) - vm.uploadJob = null - }) { - Text(text = "终止上传") - } - }, - ) - } - - is LoadStatus.Success -> { - AlertDialog(title = { Text(text = "上传完成") }, text = { - Text(text = IMPORT_BASE_URL + uploadStatusVal.result.id) - }, onDismissRequest = {}, dismissButton = { - TextButton(onClick = { - vm.uploadStatusFlow.value = null - }) { - Text(text = "关闭") - } - }, confirmButton = { - TextButton(onClick = { - ClipboardUtils.copyText(IMPORT_BASE_URL + uploadStatusVal.result.id) - toast("复制成功") - vm.uploadStatusFlow.value = null - }) { - Text(text = "复制") - } - }) - } - - else -> {} - } } diff --git a/app/src/main/kotlin/li/songe/gkd/ui/SnapshotVm.kt b/app/src/main/kotlin/li/songe/gkd/ui/SnapshotVm.kt index ee31bef..c8f4ba2 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/SnapshotVm.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/SnapshotVm.kt @@ -3,27 +3,10 @@ package li.songe.gkd.ui import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import io.ktor.client.call.body -import io.ktor.client.plugins.onUpload -import io.ktor.client.request.forms.formData -import io.ktor.client.request.forms.submitFormWithBinaryData -import io.ktor.client.statement.bodyAsText -import io.ktor.http.Headers -import io.ktor.http.HttpHeaders -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.stateIn -import li.songe.gkd.data.GithubPoliciesAsset -import li.songe.gkd.data.RpcError -import li.songe.gkd.data.Snapshot import li.songe.gkd.db.DbSet -import li.songe.gkd.debug.SnapshotExt.getSnapshotZipFile -import li.songe.gkd.util.FILE_UPLOAD_URL -import li.songe.gkd.util.LoadStatus -import li.songe.gkd.util.client -import li.songe.gkd.util.launchTry +import li.songe.gkd.ui.component.UploadOptions import javax.inject.Inject @@ -32,40 +15,6 @@ class SnapshotVm @Inject constructor() : ViewModel() { val snapshotsState = DbSet.snapshotDao.query() .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) - val uploadStatusFlow = MutableStateFlow?>(null) - var uploadJob: Job? = null - fun uploadZip(snapshot: Snapshot) { - uploadJob = viewModelScope.launchTry(Dispatchers.IO) { - val zipFile = getSnapshotZipFile(snapshot.id) - uploadStatusFlow.value = LoadStatus.Loading() - try { - val response = - client.submitFormWithBinaryData(url = FILE_UPLOAD_URL, formData = formData { - append("\"file\"", zipFile.readBytes(), Headers.build { - append(HttpHeaders.ContentType, "application/x-zip-compressed") - append(HttpHeaders.ContentDisposition, "filename=\"file.zip\"") - }) - }) { - onUpload { bytesSentTotal, contentLength -> - if (uploadStatusFlow.value is LoadStatus.Loading) { - uploadStatusFlow.value = - LoadStatus.Loading(bytesSentTotal / contentLength.toFloat()) - } - } - } - if (response.headers["X_RPC_OK"] == "true") { - val policiesAsset = response.body() - uploadStatusFlow.value = LoadStatus.Success(policiesAsset) - DbSet.snapshotDao.update(snapshot.copy(githubAssetId = policiesAsset.id)) - } else if (response.headers["X_RPC_OK"] == "false") { - uploadStatusFlow.value = LoadStatus.Failure(response.body()) - } else { - uploadStatusFlow.value = LoadStatus.Failure(Exception(response.bodyAsText())) - } - } catch (e: Exception) { - uploadStatusFlow.value = LoadStatus.Failure(e) - } - } - } + val uploadOptions = UploadOptions(viewModelScope) } \ No newline at end of file diff --git a/app/src/main/kotlin/li/songe/gkd/ui/component/UploadOptions.kt b/app/src/main/kotlin/li/songe/gkd/ui/component/UploadOptions.kt new file mode 100644 index 0000000..ea7f1f9 --- /dev/null +++ b/app/src/main/kotlin/li/songe/gkd/ui/component/UploadOptions.kt @@ -0,0 +1,146 @@ +package li.songe.gkd.ui.component + +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.LinearProgressIndicator +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import com.blankj.utilcode.util.ClipboardUtils +import io.ktor.client.call.body +import io.ktor.client.plugins.onUpload +import io.ktor.client.request.forms.formData +import io.ktor.client.request.forms.submitFormWithBinaryData +import io.ktor.client.statement.bodyAsText +import io.ktor.http.Headers +import io.ktor.http.HttpHeaders +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.MutableStateFlow +import li.songe.gkd.data.GithubPoliciesAsset +import li.songe.gkd.data.RpcError +import li.songe.gkd.util.FILE_UPLOAD_URL +import li.songe.gkd.util.LoadStatus +import li.songe.gkd.util.client +import li.songe.gkd.util.launchTry +import li.songe.gkd.util.toast +import java.io.File + +class UploadOptions( + private val scope: CoroutineScope +) { + private val statusFlow = MutableStateFlow?>(null) + private var job: Job? = null + private fun buildTask(file: File) = scope.launchTry(Dispatchers.IO) { + statusFlow.value = LoadStatus.Loading() + try { + val response = + client.submitFormWithBinaryData(url = FILE_UPLOAD_URL, formData = formData { + append("\"file\"", file.readBytes(), Headers.build { + append(HttpHeaders.ContentType, "application/x-zip-compressed") + append(HttpHeaders.ContentDisposition, "filename=\"file.zip\"") + }) + }) { + onUpload { bytesSentTotal, contentLength -> + if (statusFlow.value is LoadStatus.Loading) { + statusFlow.value = + LoadStatus.Loading(bytesSentTotal / contentLength.toFloat()) + } + } + } + if (response.headers["X_RPC_OK"] == "true") { + val policiesAsset = response.body() + statusFlow.value = LoadStatus.Success(policiesAsset) + } else if (response.headers["X_RPC_OK"] == "false") { + statusFlow.value = LoadStatus.Failure(response.body()) + } else { + statusFlow.value = LoadStatus.Failure(Exception(response.bodyAsText())) + } + } catch (e: Exception) { + statusFlow.value = LoadStatus.Failure(e) + } finally { + job = null + } + } + + fun startTask(file: File) { + if (job == null && statusFlow.value is LoadStatus.Loading) { + return + } + job = buildTask(file) + } + + private fun stopTask() { + if (statusFlow.value is LoadStatus.Loading && job != null) { + job?.cancel(CancellationException("您取消了上传")) + job = null + } + } + + + @Composable + fun ShowDialog() { + when (val status = statusFlow.collectAsState().value) { + null -> {} + is LoadStatus.Loading -> { + AlertDialog( + title = { Text(text = "上传文件中") }, + text = { + LinearProgressIndicator( + progress = { status.progress }, + ) + }, + onDismissRequest = { }, + confirmButton = { + TextButton(onClick = { + stopTask() + }) { + Text(text = "终止上传") + } + }, + ) + } + + is LoadStatus.Success -> { + AlertDialog(title = { Text(text = "上传完成") }, text = { + Text(text = status.result.shortHref) + }, onDismissRequest = {}, dismissButton = { + TextButton(onClick = { + statusFlow.value = null + }) { + Text(text = "关闭") + } + }, confirmButton = { + TextButton(onClick = { + ClipboardUtils.copyText(status.result.shortHref) + toast("复制成功") + statusFlow.value = null + }) { + Text(text = "复制并关闭") + } + }) + } + + is LoadStatus.Failure -> { + AlertDialog( + title = { Text(text = "上传失败") }, + text = { + Text(text = status.exception.let { + it.message ?: it.toString() + }) + }, + onDismissRequest = { statusFlow.value = null }, + confirmButton = { + TextButton(onClick = { + statusFlow.value = null + }) { + Text(text = "关闭") + } + }, + ) + } + } + } +} diff --git a/app/src/main/kotlin/li/songe/gkd/ui/home/HomeVm.kt b/app/src/main/kotlin/li/songe/gkd/ui/home/HomeVm.kt index bd71abc..1a53cfc 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/home/HomeVm.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/home/HomeVm.kt @@ -5,16 +5,9 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.blankj.utilcode.util.LogUtils import dagger.hilt.android.lifecycle.HiltViewModel -import io.ktor.client.call.body -import io.ktor.client.plugins.onUpload -import io.ktor.client.request.forms.formData -import io.ktor.client.request.forms.submitFormWithBinaryData import io.ktor.client.request.get import io.ktor.client.statement.bodyAsText -import io.ktor.http.Headers -import io.ktor.http.HttpHeaders import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.combine @@ -22,13 +15,9 @@ import kotlinx.coroutines.flow.debounce import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import li.songe.gkd.appScope -import li.songe.gkd.data.GithubPoliciesAsset import li.songe.gkd.data.RawSubscription -import li.songe.gkd.data.RpcError import li.songe.gkd.data.SubsItem import li.songe.gkd.db.DbSet -import li.songe.gkd.util.FILE_UPLOAD_URL -import li.songe.gkd.util.LoadStatus import li.songe.gkd.util.SortTypeOption import li.songe.gkd.util.appInfoCacheFlow import li.songe.gkd.util.clickCountFlow @@ -44,48 +33,12 @@ import li.songe.gkd.util.subsItemsFlow import li.songe.gkd.util.subsRefreshingFlow import li.songe.gkd.util.toast import li.songe.gkd.util.updateSubscription -import java.io.File import javax.inject.Inject @HiltViewModel class HomeVm @Inject constructor() : ViewModel() { val tabFlow = MutableStateFlow(controlNav) - val uploadStatusFlow = MutableStateFlow?>(null) - var uploadJob: Job? = null - - fun uploadZip(zipFile: File) { - uploadJob = viewModelScope.launchTry(Dispatchers.IO) { - uploadStatusFlow.value = LoadStatus.Loading() - try { - val response = - client.submitFormWithBinaryData(url = FILE_UPLOAD_URL, formData = formData { - append("\"file\"", zipFile.readBytes(), Headers.build { - append(HttpHeaders.ContentType, "application/x-zip-compressed") - append(HttpHeaders.ContentDisposition, "filename=\"file.zip\"") - }) - }) { - onUpload { bytesSentTotal, contentLength -> - if (uploadStatusFlow.value is LoadStatus.Loading) { - uploadStatusFlow.value = - LoadStatus.Loading(bytesSentTotal / contentLength.toFloat()) - } - } - } - if (response.headers["X_RPC_OK"] == "true") { - val policiesAsset = response.body() - uploadStatusFlow.value = LoadStatus.Success(policiesAsset) - } else if (response.headers["X_RPC_OK"] == "false") { - uploadStatusFlow.value = LoadStatus.Failure(response.body()) - } else { - uploadStatusFlow.value = LoadStatus.Failure(Exception(response.bodyAsText())) - } - } catch (e: Exception) { - uploadStatusFlow.value = LoadStatus.Failure(e) - } - } - } - private val latestRecordFlow = DbSet.clickLogDao.queryLatest().stateIn(viewModelScope, SharingStarted.Eagerly, null) val latestRecordDescFlow = combine( diff --git a/app/src/main/kotlin/li/songe/gkd/ui/home/SettingsPage.kt b/app/src/main/kotlin/li/songe/gkd/ui/home/SettingsPage.kt index cb55feb..1174949 100644 --- a/app/src/main/kotlin/li/songe/gkd/ui/home/SettingsPage.kt +++ b/app/src/main/kotlin/li/songe/gkd/ui/home/SettingsPage.kt @@ -9,17 +9,13 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.HelpOutline -import androidx.compose.material.icons.filled.Upload import androidx.compose.material.icons.outlined.Settings import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Card import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text @@ -35,20 +31,12 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.viewModelScope -import com.blankj.utilcode.util.ClipboardUtils -import com.blankj.utilcode.util.LogUtils import com.ramcosta.composedestinations.navigation.navigate -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.update import li.songe.gkd.BuildConfig.ENABLED_UPDATE -import li.songe.gkd.MainActivity import li.songe.gkd.ui.component.RotatingLoadingIcon import li.songe.gkd.ui.component.SettingItem import li.songe.gkd.ui.component.TextMenu @@ -61,17 +49,12 @@ import li.songe.gkd.ui.style.itemPadding import li.songe.gkd.ui.style.titleItemPadding import li.songe.gkd.ui.theme.supportDynamicColor import li.songe.gkd.util.DarkThemeOption -import li.songe.gkd.util.LoadStatus import li.songe.gkd.util.LocalMainViewModel import li.songe.gkd.util.LocalNavController import li.songe.gkd.util.UpdateTimeOption -import li.songe.gkd.util.buildLogFile import li.songe.gkd.util.checkUpdate import li.songe.gkd.util.findOption import li.songe.gkd.util.launchAsFn -import li.songe.gkd.util.launchTry -import li.songe.gkd.util.saveFileToDownloads -import li.songe.gkd.util.shareFile import li.songe.gkd.util.storeFlow import li.songe.gkd.util.throttle import li.songe.gkd.util.toast @@ -82,12 +65,10 @@ val settingsNav = BottomNavItem( @Composable fun useSettingsPage(): ScaffoldExt { - val context = LocalContext.current as MainActivity val mainVm = LocalMainViewModel.current val navController = LocalNavController.current val store by storeFlow.collectAsState() val vm = hiltViewModel() - val uploadStatus by vm.uploadStatusFlow.collectAsState() var showToastInputDlg by remember { mutableStateOf(false) @@ -96,10 +77,6 @@ fun useSettingsPage(): ScaffoldExt { mutableStateOf(false) } - var showShareLogDlg by remember { - mutableStateOf(false) - } - val checkUpdating by mainVm.updateStatus.checkUpdatingFlow.collectAsState() if (showToastInputDlg) { @@ -210,118 +187,6 @@ fun useSettingsPage(): ScaffoldExt { }) } - if (showShareLogDlg) { - Dialog(onDismissRequest = { showShareLogDlg = false }) { - Card( - modifier = Modifier - .fillMaxWidth() - .padding(16.dp), - shape = RoundedCornerShape(16.dp), - ) { - val modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - Text( - text = "分享到其他应用", modifier = Modifier - .clickable(onClick = throttle { - showShareLogDlg = false - vm.viewModelScope.launchTry(Dispatchers.IO) { - val logZipFile = buildLogFile() - context.shareFile(logZipFile, "分享日志文件") - } - }) - .then(modifier) - ) - Text( - text = "保存到下载", modifier = Modifier - .clickable(onClick = throttle { - showShareLogDlg = false - vm.viewModelScope.launchTry(Dispatchers.IO) { - val logZipFile = buildLogFile() - context.saveFileToDownloads(logZipFile) - } - }) - .then(modifier) - ) - Text( - text = "生成链接(需科学上网)", - modifier = Modifier - .clickable(onClick = throttle { - showShareLogDlg = false - vm.viewModelScope.launchTry(Dispatchers.IO) { - val logZipFile = buildLogFile() - vm.uploadZip(logZipFile) - } - }) - .then(modifier) - ) - } - } - } - - when (val uploadStatusVal = uploadStatus) { - is LoadStatus.Failure -> { - AlertDialog( - title = { Text(text = "上传失败") }, - text = { - Text(text = uploadStatusVal.exception.let { - it.message ?: it.toString() - }) - }, - onDismissRequest = { vm.uploadStatusFlow.value = null }, - confirmButton = { - TextButton(onClick = { - vm.uploadStatusFlow.value = null - }) { - Text(text = "关闭") - } - }, - ) - } - - is LoadStatus.Loading -> { - AlertDialog( - title = { Text(text = "上传文件中") }, - text = { - LinearProgressIndicator( - progress = { uploadStatusVal.progress }, - ) - }, - onDismissRequest = { }, - confirmButton = { - TextButton(onClick = { - vm.uploadJob?.cancel(CancellationException("终止上传")) - vm.uploadJob = null - }) { - Text(text = "终止上传") - } - }, - ) - } - - is LoadStatus.Success -> { - AlertDialog(title = { Text(text = "上传完成") }, text = { - Text(text = uploadStatusVal.result.shortHref) - }, onDismissRequest = {}, dismissButton = { - TextButton(onClick = { - vm.uploadStatusFlow.value = null - }) { - Text(text = "关闭") - } - }, confirmButton = { - TextButton(onClick = { - ClipboardUtils.copyText(uploadStatusVal.result.shortHref) - toast("复制成功") - vm.uploadStatusFlow.value = null - }) { - Text(text = "复制") - } - }) - } - - else -> {} - } - val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val scrollState = rememberScrollState() return ScaffoldExt( @@ -470,37 +335,6 @@ fun useSettingsPage(): ScaffoldExt { } } - Text( - text = "日志", - modifier = Modifier.titleItemPadding(), - style = MaterialTheme.typography.titleSmall, - color = MaterialTheme.colorScheme.primary, - ) - - TextSwitch(name = "保存日志", - desc = "保存7天日志,帮助定位BUG", - checked = store.log2FileSwitch, - onCheckedChange = { - storeFlow.value = store.copy( - log2FileSwitch = it - ) - if (!it) { - mainVm.viewModelScope.launchTry(Dispatchers.IO) { - val logFiles = LogUtils.getLogFiles() - if (logFiles.isNotEmpty()) { - logFiles.forEach { f -> - f.delete() - } - toast("已删除全部日志") - } - } - } - }) - - SettingItem(title = "导出日志", imageVector = Icons.Default.Upload, onClick = { - showShareLogDlg = true - }) - Text( text = "其它", modifier = Modifier.titleItemPadding(),