Skip to content

Commit

Permalink
perf: share save file
Browse files Browse the repository at this point in the history
  • Loading branch information
lisonge committed Aug 2, 2024
1 parent 36621c3 commit 8c12ee1
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 30 deletions.
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

<!-- save image to album -->
<!-- save image to album, save file to Downloads -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
Expand Down
8 changes: 3 additions & 5 deletions app/src/main/kotlin/li/songe/gkd/data/TransferData.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package li.songe.gkd.data

import android.content.Context
import android.net.Uri
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.UriUtils
Expand All @@ -17,11 +16,11 @@ import li.songe.gkd.util.exportZipDir
import li.songe.gkd.util.importZipDir
import li.songe.gkd.util.json
import li.songe.gkd.util.resetDirectory
import li.songe.gkd.util.shareFile
import li.songe.gkd.util.subsIdToRawFlow
import li.songe.gkd.util.subsItemsFlow
import li.songe.gkd.util.toast
import li.songe.gkd.util.updateSubscription
import java.io.File

@Serializable
private data class TransferData(
Expand Down Expand Up @@ -52,8 +51,7 @@ private suspend fun importTransferData(transferData: TransferData): Boolean {
return hasNewSubsItem
}

suspend fun exportData(context: Context, subsIds: Collection<Long>) {
if (subsIds.isEmpty()) return
suspend fun exportData(subsIds: Collection<Long>):File {
exportZipDir.resetDirectory()
val dataFile = exportZipDir.resolve("${TransferData.TYPE}.json")
dataFile.writeText(
Expand All @@ -74,7 +72,7 @@ suspend fun exportData(context: Context, subsIds: Collection<Long>) {
ZipUtils.zipFiles(listOf(dataFile, files), file)
dataFile.delete()
files.deleteRecursively()
context.shareFile(file, "分享数据文件")
return file
}

suspend fun importData(uri: Uri) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ val canDrawOverlaysState by lazy {
)
}

val canSaveToAlbumState by lazy {
val canWriteExternalStorage by lazy {
PermissionState(
check = {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
Expand Down Expand Up @@ -170,7 +170,7 @@ suspend fun updatePermissionState() {
arrayOf(
notificationState,
canDrawOverlaysState,
canSaveToAlbumState,
canWriteExternalStorage,
shizukuOkState
).forEach { it.updateAndGet() }
if (canQueryPkgState.stateFlow.value != canQueryPkgState.updateAndGet()) {
Expand Down
33 changes: 24 additions & 9 deletions app/src/main/kotlin/li/songe/gkd/ui/SnapshotPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import li.songe.gkd.MainActivity
import li.songe.gkd.data.Snapshot
import li.songe.gkd.db.DbSet
import li.songe.gkd.debug.SnapshotExt
import li.songe.gkd.permission.canSaveToAlbumState
import li.songe.gkd.permission.canWriteExternalStorage
import li.songe.gkd.permission.requiredPermission
import li.songe.gkd.ui.component.StartEllipsisText
import li.songe.gkd.ui.destinations.ImagePreviewPageDestination
Expand All @@ -66,6 +66,7 @@ import li.songe.gkd.util.LocalNavController
import li.songe.gkd.util.LocalPickContentLauncher
import li.songe.gkd.util.ProfileTransitions
import li.songe.gkd.util.launchAsFn
import li.songe.gkd.util.saveFileToDownloads
import li.songe.gkd.util.shareFile
import li.songe.gkd.util.snapshotZipDir
import li.songe.gkd.util.throttle
Expand Down Expand Up @@ -195,17 +196,31 @@ fun SnapshotPage() {
)
HorizontalDivider()
Text(
text = "分享",
text = "分享数据",
modifier = Modifier
.clickable(onClick = vm.viewModelScope.launchAsFn {
val zipFile =
SnapshotExt.getSnapshotZipFile(
snapshotVal.id,
snapshotVal.appId,
snapshotVal.activityId
)
selectedSnapshot = null
val zipFile = SnapshotExt.getSnapshotZipFile(
snapshotVal.id,
snapshotVal.appId,
snapshotVal.activityId
)
context.shareFile(zipFile, "分享快照文件")
})
.then(modifier)
)
HorizontalDivider()
Text(
text = "保存到下载",
modifier = Modifier
.clickable(onClick = vm.viewModelScope.launchAsFn {
selectedSnapshot = null
val zipFile = SnapshotExt.getSnapshotZipFile(
snapshotVal.id,
snapshotVal.appId,
snapshotVal.activityId
)
context.saveFileToDownloads(zipFile)
})
.then(modifier)
)
Expand Down Expand Up @@ -236,7 +251,7 @@ fun SnapshotPage() {
text = "保存截图到相册",
modifier = Modifier
.clickable(onClick = vm.viewModelScope.launchAsFn {
requiredPermission(context, canSaveToAlbumState)
requiredPermission(context, canWriteExternalStorage)
ImageUtils.save2Album(
ImageUtils.getBitmap(snapshotVal.screenshotFile),
Bitmap.CompressFormat.PNG,
Expand Down
9 changes: 4 additions & 5 deletions app/src/main/kotlin/li/songe/gkd/ui/component/SubsItemCard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,17 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ClipboardUtils
import com.ramcosta.composedestinations.navigation.navigate
import kotlinx.coroutines.Dispatchers
import li.songe.gkd.data.RawSubscription
import li.songe.gkd.data.SubsItem
import li.songe.gkd.data.deleteSubscription
import li.songe.gkd.data.exportData
import li.songe.gkd.ui.destinations.CategoryPageDestination
import li.songe.gkd.ui.destinations.GlobalRulePageDestination
import li.songe.gkd.ui.destinations.SubsPageDestination
import li.songe.gkd.ui.home.HomeVm
import li.songe.gkd.util.LOCAL_SUBS_ID
import li.songe.gkd.util.LocalMainViewModel
import li.songe.gkd.util.LocalNavController
Expand All @@ -61,7 +60,7 @@ fun SubsItemCard(
subsItem: SubsItem,
subscription: RawSubscription?,
index: Int,
vm: ViewModel,
vm: HomeVm,
isSelectedMode: Boolean,
isSelected: Boolean,
onCheckedChange: ((Boolean) -> Unit)? = null,
Expand Down Expand Up @@ -192,7 +191,7 @@ private fun SubsMenuItem(
onExpandedChange: ((Boolean) -> Unit),
subItem: SubsItem,
subscription: RawSubscription?,
vm: ViewModel
vm: HomeVm
) {
val navController = LocalNavController.current
val context = LocalContext.current
Expand Down Expand Up @@ -243,7 +242,7 @@ private fun SubsMenuItem(
onClick = {
onExpandedChange(false)
vm.viewModelScope.launchTry(Dispatchers.IO) {
exportData(context, listOf(subItem.id))
vm.showShareDataIdsFlow.value = setOf(subItem.id)
}
}
)
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/kotlin/li/songe/gkd/ui/home/HomeVm.kt
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,6 @@ class HomeVm @Inject constructor() : ViewModel() {

val clickLogCountFlow =
DbSet.clickLogDao.count().stateIn(viewModelScope, SharingStarted.Eagerly, 0)

val showShareDataIdsFlow = MutableStateFlow<Set<Long>?>(null)
}
14 changes: 13 additions & 1 deletion app/src/main/kotlin/li/songe/gkd/ui/home/SettingsPage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ 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
Expand Down Expand Up @@ -149,7 +150,7 @@ fun useSettingsPage(): ScaffoldExt {
.fillMaxWidth()
.padding(16.dp)
Text(
text = "调用系统分享", modifier = Modifier
text = "分享数据", modifier = Modifier
.clickable(onClick = throttle {
showShareLogDlg = false
vm.viewModelScope.launchTry(Dispatchers.IO) {
Expand All @@ -159,6 +160,17 @@ fun useSettingsPage(): ScaffoldExt {
})
.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
Expand Down
60 changes: 55 additions & 5 deletions app/src/main/kotlin/li/songe/gkd/ui/home/SubsManagePage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package li.songe.gkd.ui.home
import android.content.Intent
import android.webkit.URLUtil
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand All @@ -16,6 +17,7 @@ import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.FormatListBulleted
import androidx.compose.material.icons.filled.Add
Expand All @@ -24,6 +26,7 @@ import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Card
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.FloatingActionButton
Expand Down Expand Up @@ -51,19 +54,20 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.viewModelScope
import com.dylanc.activityresult.launcher.launchForResult
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import li.songe.gkd.MainActivity
import li.songe.gkd.data.Value
import li.songe.gkd.data.deleteSubscription
import li.songe.gkd.data.exportData
import li.songe.gkd.data.importData
import li.songe.gkd.db.DbSet
import li.songe.gkd.ui.component.SubsItemCard
import li.songe.gkd.ui.component.getResult
import li.songe.gkd.ui.component.waitResult
import li.songe.gkd.util.LOCAL_SUBS_ID
import li.songe.gkd.util.LocalLauncher
Expand All @@ -72,9 +76,12 @@ import li.songe.gkd.util.checkSubsUpdate
import li.songe.gkd.util.isSafeUrl
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.subsIdToRawFlow
import li.songe.gkd.util.subsItemsFlow
import li.songe.gkd.util.subsRefreshingFlow
import li.songe.gkd.util.throttle
import li.songe.gkd.util.toast
import sh.calvin.reorderable.ReorderableItem
import sh.calvin.reorderable.rememberReorderableLazyListState
Expand All @@ -86,7 +93,6 @@ val subsNav = BottomNavItem(
@Composable
fun useSubsManagePage(): ScaffoldExt {
val launcher = LocalLauncher.current
val context = LocalContext.current
val mainVm = LocalMainViewModel.current

val vm = hiltViewModel<HomeVm>()
Expand Down Expand Up @@ -171,6 +177,8 @@ fun useSubsManagePage(): ScaffoldExt {
})
}

ShareDataDialog(vm)

val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
return ScaffoldExt(
navItem = subsNav,
Expand Down Expand Up @@ -205,11 +213,10 @@ fun useSubsManagePage(): ScaffoldExt {
}
if (canDeleteIds.isNotEmpty()) {
IconButton(onClick = vm.viewModelScope.launchAsFn {
val result = mainVm.dialogFlow.getResult(
mainVm.dialogFlow.waitResult(
title = "删除订阅",
text = "是否删除所选 ${canDeleteIds.size} 个订阅?\n\n注: 不包含本地订阅",
)
if (!result) return@launchAsFn
deleteSubscription(*canDeleteIds.toLongArray())
selectedIds = selectedIds - canDeleteIds
if (selectedIds.size == canDeleteIds.size) {
Expand All @@ -223,7 +230,7 @@ fun useSubsManagePage(): ScaffoldExt {
}
}
IconButton(onClick = vm.viewModelScope.launchAsFn(Dispatchers.IO) {
exportData(context, selectedIds)
vm.showShareDataIdsFlow.value = selectedIds
}) {
Icon(
imageVector = Icons.Default.Share,
Expand Down Expand Up @@ -425,4 +432,47 @@ fun useSubsManagePage(): ScaffoldExt {
)
}
}
}

@Composable
private fun ShareDataDialog(vm: HomeVm) {
val context = LocalContext.current as MainActivity
val showShareDataIds = vm.showShareDataIdsFlow.collectAsState().value
if (showShareDataIds != null) {
Dialog(onDismissRequest = { vm.showShareDataIdsFlow.value = null }) {
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 {
vm.showShareDataIdsFlow.value = null
vm.viewModelScope.launchTry(Dispatchers.IO) {
val file = exportData(showShareDataIds)
context.shareFile(file, "分享数据文件")
}
})
.then(modifier)
)
Text(
text = "保存到下载",
modifier = Modifier
.clickable(onClick = throttle {
vm.showShareDataIdsFlow.value = null
vm.viewModelScope.launchTry(Dispatchers.IO) {
val file = exportData(showShareDataIds)
context.saveFileToDownloads(file)
}
})
.then(modifier)
)
}
}
}
}
Loading

0 comments on commit 8c12ee1

Please sign in to comment.