perf: upload github file link

This commit is contained in:
二刺螈 2024-11-13 22:01:05 +08:00
parent c07d29e876
commit 53a035bcd9
9 changed files with 118 additions and 89 deletions

View File

@ -44,6 +44,7 @@ import li.songe.gkd.service.fixRestartService
import li.songe.gkd.service.updateLauncherAppId
import li.songe.gkd.ui.component.BuildDialog
import li.songe.gkd.ui.theme.AppTheme
import li.songe.gkd.util.EditGithubCookieDlg
import li.songe.gkd.util.LocalNavController
import li.songe.gkd.util.UpgradeDialog
import li.songe.gkd.util.appInfoCacheFlow
@ -93,6 +94,8 @@ class MainActivity : ComponentActivity() {
ShizukuErrorDialog(mainVm.shizukuErrorFlow)
AuthDialog(mainVm.authReasonFlow)
BuildDialog(mainVm.dialogFlow)
mainVm.uploadOptions.ShowDialog()
EditGithubCookieDlg(mainVm.showEditCookieDlgFlow)
if (META.updateEnabled) {
UpgradeDialog(mainVm.updateStatus)
}

View File

@ -15,6 +15,7 @@ import li.songe.gkd.data.SubsItem
import li.songe.gkd.db.DbSet
import li.songe.gkd.permission.AuthReason
import li.songe.gkd.ui.component.AlertDialogOptions
import li.songe.gkd.ui.component.UploadOptions
import li.songe.gkd.util.LOCAL_SUBS_ID
import li.songe.gkd.util.UpdateStatus
import li.songe.gkd.util.checkUpdate
@ -43,6 +44,10 @@ class MainViewModel : ViewModel() {
val shizukuErrorFlow = MutableStateFlow(false)
val uploadOptions = UploadOptions(this)
val showEditCookieDlgFlow = MutableStateFlow(false)
init {
viewModelScope.launchTry(Dispatchers.IO) {
val subsItems = DbSet.subsItemDao.queryAll()

View File

@ -48,7 +48,6 @@ import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import kotlinx.coroutines.Dispatchers
@ -88,10 +87,8 @@ import li.songe.gkd.util.toast
fun AboutPage() {
val navController = LocalNavController.current
val context = LocalContext.current as MainActivity
val vm = viewModel<AboutVm>()
val store by storeFlow.collectAsState()
vm.uploadOptions.ShowDialog()
var showInfoDlg by remember { mutableStateOf(false) }
if (showInfoDlg) {
AlertDialog(
@ -176,7 +173,9 @@ fun AboutPage() {
modifier = Modifier
.clickable(onClick = throttle {
showShareLogDlg = false
vm.uploadOptions.startTask(getFile = { buildLogFile() })
context.mainVm.uploadOptions.startTask(
getFile = { buildLogFile() }
)
})
.then(modifier)
)

View File

@ -1,9 +0,0 @@
package li.songe.gkd.ui
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import li.songe.gkd.ui.component.UploadOptions
class AboutVm : ViewModel() {
val uploadOptions = UploadOptions(viewModelScope)
}

View File

@ -5,7 +5,6 @@ import android.content.Context
import android.media.projection.MediaProjectionManager
import android.os.Build
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -19,7 +18,6 @@ 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.automirrored.outlined.HelpOutline
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon
@ -58,7 +56,6 @@ import com.ramcosta.composedestinations.generated.destinations.ActivityLogPageDe
import com.ramcosta.composedestinations.generated.destinations.SnapshotPageDestination
import com.ramcosta.composedestinations.utils.toDestinationsNavigator
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.update
import li.songe.gkd.MainActivity
import li.songe.gkd.appScope
import li.songe.gkd.debug.FloatingService
@ -81,7 +78,6 @@ import li.songe.gkd.util.LocalNavController
import li.songe.gkd.util.ProfileTransitions
import li.songe.gkd.util.launchAsFn
import li.songe.gkd.util.openUri
import li.songe.gkd.util.privacyStoreFlow
import li.songe.gkd.util.storeFlow
import li.songe.gkd.util.throttle
import li.songe.gkd.util.toast
@ -155,62 +151,6 @@ fun AdvancedPage() {
})
}
var showEditCookieDlg by remember { mutableStateOf(false) }
if (showEditCookieDlg) {
val privacyStore by privacyStoreFlow.collectAsState()
var value by remember {
mutableStateOf(privacyStore.githubCookie ?: "")
}
AlertDialog(
onDismissRequest = {
if (value.isEmpty()) {
showEditCookieDlg = false
}
},
title = {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth(),
) {
Text(text = "Github Cookie")
IconButton(onClick = throttle {
context.openUri("https://gkd.li/?r=1")
}) {
Icon(
imageVector = Icons.AutoMirrored.Outlined.HelpOutline,
contentDescription = null,
)
}
}
},
text = {
OutlinedTextField(
value = value,
onValueChange = {
value = it.filter { c -> c != '\n' && c != '\r' }
},
placeholder = { Text(text = "请输入 Github Cookie") },
modifier = Modifier.fillMaxWidth(),
maxLines = 10,
)
},
confirmButton = {
TextButton(onClick = {
showEditCookieDlg = false
privacyStoreFlow.update { it.copy(githubCookie = value.trim()) }
}) {
Text(text = "确认")
}
},
dismissButton = {
TextButton(onClick = { showEditCookieDlg = false }) {
Text(text = "取消")
}
}
)
}
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
@ -454,7 +394,7 @@ fun AdvancedPage() {
},
imageVector = Icons.Default.Edit,
onClick = {
showEditCookieDlg = true
context.mainVm.showEditCookieDlgFlow.value = true
}
)

View File

@ -79,8 +79,6 @@ fun SnapshotPage() {
val vm = viewModel<SnapshotVm>()
val snapshots by vm.snapshotsState.collectAsState()
vm.uploadOptions.ShowDialog()
var selectedSnapshot by remember {
mutableStateOf<Snapshot?>(null)
}
@ -246,8 +244,9 @@ fun SnapshotPage() {
text = "生成链接(需科学上网)", modifier = Modifier
.clickable(onClick = throttle {
selectedSnapshot = null
vm.uploadOptions.startTask(
context.mainVm.uploadOptions.startTask(
getFile = { SnapshotExt.getSnapshotZipFile(snapshotVal.id) },
showHref = { IMPORT_SHORT_URL + it.id },
onSuccessResult = vm.viewModelScope.launchAsFn<GithubPoliciesAsset>(
Dispatchers.IO
) {

View File

@ -5,15 +5,8 @@ import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.stateIn
import li.songe.gkd.db.DbSet
import li.songe.gkd.ui.component.UploadOptions
import li.songe.gkd.util.IMPORT_SHORT_URL
class SnapshotVm : ViewModel() {
val snapshotsState = DbSet.snapshotDao.query()
.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
val uploadOptions = UploadOptions(
scope = viewModelScope,
showHref = { IMPORT_SHORT_URL + it.id }
)
}

View File

@ -6,13 +6,15 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ClipboardUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.MutableStateFlow
import li.songe.gkd.MainViewModel
import li.songe.gkd.data.GithubPoliciesAsset
import li.songe.gkd.util.GithubCookieException
import li.songe.gkd.util.LoadStatus
import li.songe.gkd.util.launchTry
import li.songe.gkd.util.privacyStoreFlow
@ -21,8 +23,7 @@ import li.songe.gkd.util.uploadFileToGithub
import java.io.File
class UploadOptions(
private val scope: CoroutineScope,
private val showHref: (GithubPoliciesAsset) -> String = { it.shortHref }
private val mainVm: MainViewModel,
) {
private val statusFlow = MutableStateFlow<LoadStatus<GithubPoliciesAsset>?>(null)
private var job: Job? = null
@ -30,7 +31,7 @@ class UploadOptions(
cookie: String,
getFile: suspend () -> File,
onSuccessResult: ((GithubPoliciesAsset) -> Unit)?
) = scope.launchTry(Dispatchers.IO) {
) = mainVm.viewModelScope.launchTry(Dispatchers.IO) {
statusFlow.value = LoadStatus.Loading()
try {
val policiesAsset = uploadFileToGithub(cookie, getFile()) {
@ -47,18 +48,23 @@ class UploadOptions(
}
}
private var showHref: (GithubPoliciesAsset) -> String = { it.shortHref }
fun startTask(
getFile: suspend () -> File,
showHref: (GithubPoliciesAsset) -> String = { it.shortHref },
onSuccessResult: ((GithubPoliciesAsset) -> Unit)? = null
) {
val cookie = privacyStoreFlow.value.githubCookie
if (cookie.isNullOrBlank()) {
toast("请先设置 cookie 后再上传")
mainVm.showEditCookieDlgFlow.value = true
return
}
if (job != null || statusFlow.value is LoadStatus.Loading) {
return
}
this.showHref = showHref
job = buildTask(cookie, getFile, onSuccessResult)
}
@ -123,6 +129,16 @@ class UploadOptions(
})
},
onDismissRequest = { statusFlow.value = null },
dismissButton = if (status.exception is GithubCookieException) ({
TextButton(onClick = {
statusFlow.value = null
mainVm.showEditCookieDlgFlow.value = true
}) {
Text(text = "更换 Cookie")
}
}) else {
null
},
confirmButton = {
TextButton(onClick = {
statusFlow.value = null

View File

@ -1,5 +1,24 @@
package li.songe.gkd.util
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import io.ktor.client.call.body
import io.ktor.client.plugins.onUpload
import io.ktor.client.request.forms.MultiPartFormDataContent
@ -13,7 +32,10 @@ import io.ktor.client.statement.bodyAsText
import io.ktor.http.Headers
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpMessageBuilder
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.serialization.Serializable
import li.songe.gkd.app
import li.songe.gkd.data.GithubPoliciesAsset
import java.io.File
@ -50,12 +72,14 @@ private data class Authenticity(
val authenticityToken: String,
)
data class GithubCookieException(override val message: String) : Exception(message)
private suspend fun getAuthenticity(cookie: String): Authenticity {
val text = client.get(GITHUB_UPLOAD_URL) {
setCommonHeaders(cookie)
}.bodyAsText()
if (!text.contains("data-login")) {
error("用户未登录, 请更换 cookie")
throw GithubCookieException("未检测到用户登录, 请更换 cookie")
}
val repositoryId =
repositoryIdRegex.find(text)?.groupValues?.get(1) ?: error("repositoryId not found")
@ -114,3 +138,62 @@ suspend fun uploadFileToGithub(
return policiesResp.asset
}
@Composable
fun EditGithubCookieDlg(showEditCookieDlgFlow: MutableStateFlow<Boolean>) {
val showEditCookieDlg by showEditCookieDlgFlow.collectAsState()
if (showEditCookieDlg) {
val privacyStore by privacyStoreFlow.collectAsState()
var value by remember {
mutableStateOf(privacyStore.githubCookie ?: "")
}
AlertDialog(
onDismissRequest = {
if (value.isEmpty()) {
showEditCookieDlgFlow.value = false
}
},
title = {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth(),
) {
Text(text = "Github Cookie")
IconButton(onClick = throttle {
app.openUri("https://gkd.li/?r=1")
}) {
Icon(
imageVector = Icons.AutoMirrored.Outlined.HelpOutline,
contentDescription = null,
)
}
}
},
text = {
OutlinedTextField(
value = value,
onValueChange = {
value = it.filter { c -> c != '\n' && c != '\r' }
},
placeholder = { Text(text = "请输入 Github Cookie") },
modifier = Modifier.fillMaxWidth(),
maxLines = 10,
)
},
confirmButton = {
TextButton(onClick = {
showEditCookieDlgFlow.value = false
privacyStoreFlow.update { it.copy(githubCookie = value.trim()) }
}) {
Text(text = "确认")
}
},
dismissButton = {
TextButton(onClick = { showEditCookieDlgFlow.value = false }) {
Text(text = "取消")
}
}
)
}
}