mirror of
https://github.com/gkd-kit/gkd.git
synced 2024-11-16 11:42:22 +08:00
This commit is contained in:
parent
a57fe608f9
commit
58f367b72b
|
@ -1,19 +1,33 @@
|
||||||
package li.songe.gkd.data
|
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
|
||||||
|
import com.blankj.utilcode.util.ZipUtils
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
import li.songe.gkd.db.DbSet
|
import li.songe.gkd.db.DbSet
|
||||||
import li.songe.gkd.util.LOCAL_SUBS_IDS
|
import li.songe.gkd.util.LOCAL_SUBS_IDS
|
||||||
|
import li.songe.gkd.util.checkSubsUpdate
|
||||||
|
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.subsIdToRawFlow
|
||||||
import li.songe.gkd.util.subsItemsFlow
|
import li.songe.gkd.util.subsItemsFlow
|
||||||
|
import li.songe.gkd.util.toast
|
||||||
import li.songe.gkd.util.updateSubscription
|
import li.songe.gkd.util.updateSubscription
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class TransferData(
|
private data class TransferData(
|
||||||
val type: String = TYPE,
|
val type: String = TYPE,
|
||||||
val ctime: Long = System.currentTimeMillis(),
|
val ctime: Long = System.currentTimeMillis(),
|
||||||
|
|
||||||
val subsItems: List<SubsItem> = emptyList(),
|
val subsItems: List<SubsItem> = emptyList(),
|
||||||
val subscriptions: List<RawSubscription> = emptyList(),
|
|
||||||
val subsConfigs: List<SubsConfig> = emptyList(),
|
val subsConfigs: List<SubsConfig> = emptyList(),
|
||||||
val categoryConfigs: List<CategoryConfig> = emptyList(),
|
val categoryConfigs: List<CategoryConfig> = emptyList(),
|
||||||
) {
|
) {
|
||||||
|
@ -22,16 +36,7 @@ data class TransferData(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun exportTransferData(subsItemIds: Collection<Long>): TransferData {
|
private suspend fun importTransferData(transferData: TransferData): Boolean {
|
||||||
return TransferData(
|
|
||||||
subsItems = subsItemsFlow.value.filter { subsItemIds.contains(it.id) },
|
|
||||||
subscriptions = subsIdToRawFlow.value.values.filter { it.id < 0 && subsItemIds.contains(it.id) },
|
|
||||||
subsConfigs = DbSet.subsConfigDao.querySubsItemConfig(subsItemIds.toList()),
|
|
||||||
categoryConfigs = DbSet.categoryConfigDao.querySubsItemConfig(subsItemIds.toList()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun importTransferData(transferData: TransferData): Boolean {
|
|
||||||
// TODO transaction
|
// TODO transaction
|
||||||
val maxOrder = (subsItemsFlow.value.maxOfOrNull { it.order } ?: -1) + 1
|
val maxOrder = (subsItemsFlow.value.maxOfOrNull { it.order } ?: -1) + 1
|
||||||
val subsItems =
|
val subsItems =
|
||||||
|
@ -44,10 +49,68 @@ suspend fun importTransferData(transferData: TransferData): Boolean {
|
||||||
DbSet.subsItemDao.insertOrIgnore(*subsItems.toTypedArray())
|
DbSet.subsItemDao.insertOrIgnore(*subsItems.toTypedArray())
|
||||||
DbSet.subsConfigDao.insertOrIgnore(*transferData.subsConfigs.toTypedArray())
|
DbSet.subsConfigDao.insertOrIgnore(*transferData.subsConfigs.toTypedArray())
|
||||||
DbSet.categoryConfigDao.insertOrIgnore(*transferData.categoryConfigs.toTypedArray())
|
DbSet.categoryConfigDao.insertOrIgnore(*transferData.categoryConfigs.toTypedArray())
|
||||||
transferData.subscriptions.forEach { subscription ->
|
return hasNewSubsItem
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun exportData(context: Context, subsIds: Collection<Long>) {
|
||||||
|
if (subsIds.isEmpty()) return
|
||||||
|
exportZipDir.resetDirectory()
|
||||||
|
val dataFile = exportZipDir.resolve("${TransferData.TYPE}.json")
|
||||||
|
dataFile.writeText(
|
||||||
|
json.encodeToString(
|
||||||
|
TransferData(
|
||||||
|
subsItems = subsItemsFlow.value.filter { subsIds.contains(it.id) },
|
||||||
|
subsConfigs = DbSet.subsConfigDao.querySubsItemConfig(subsIds.toList()),
|
||||||
|
categoryConfigs = DbSet.categoryConfigDao.querySubsItemConfig(subsIds.toList()),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val files = exportZipDir.resolve("files").apply { mkdir() }
|
||||||
|
subsIdToRawFlow.value.values.filter { it.id < 0 && subsIds.contains(it.id) }.forEach {
|
||||||
|
val file = files.resolve("${it.id}.json")
|
||||||
|
file.writeText(json.encodeToString(it))
|
||||||
|
}
|
||||||
|
val file = exportZipDir.resolve("backup-${System.currentTimeMillis()}.zip")
|
||||||
|
ZipUtils.zipFiles(listOf(dataFile, files), file)
|
||||||
|
dataFile.delete()
|
||||||
|
files.deleteRecursively()
|
||||||
|
context.shareFile(file, "分享数据文件")
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun importData(uri: Uri) {
|
||||||
|
importZipDir.resetDirectory()
|
||||||
|
val zipFile = importZipDir.resolve("import.zip")
|
||||||
|
zipFile.writeBytes(UriUtils.uri2Bytes(uri))
|
||||||
|
val unZipImportFile = importZipDir.resolve("unzipImport")
|
||||||
|
ZipUtils.unzipFile(zipFile, unZipImportFile)
|
||||||
|
val transferFile = unZipImportFile.resolve("${TransferData.TYPE}.json")
|
||||||
|
if (!transferFile.exists() || !transferFile.isFile) {
|
||||||
|
toast("导入无数据")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val data = withContext(Dispatchers.Default) {
|
||||||
|
json.decodeFromString<TransferData>(transferFile.readText())
|
||||||
|
}
|
||||||
|
val hasNewSubsItem = importTransferData(data)
|
||||||
|
val files = unZipImportFile.resolve("files")
|
||||||
|
val subscriptions = (files.listFiles { f -> f.isFile && f.name.endsWith(".json") }
|
||||||
|
?: emptyArray()).mapNotNull { f ->
|
||||||
|
try {
|
||||||
|
RawSubscription.parse(f.readText())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LogUtils.d(e)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subscriptions.forEach { subscription ->
|
||||||
if (LOCAL_SUBS_IDS.contains(subscription.id)) {
|
if (LOCAL_SUBS_IDS.contains(subscription.id)) {
|
||||||
updateSubscription(subscription)
|
updateSubscription(subscription)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hasNewSubsItem
|
toast("导入成功")
|
||||||
|
importZipDir.resetDirectory()
|
||||||
|
if (hasNewSubsItem) {
|
||||||
|
delay(1000)
|
||||||
|
checkSubsUpdate(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package li.songe.gkd.ui.component
|
package li.songe.gkd.ui.component
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.interaction.collectIsDraggedAsState
|
import androidx.compose.foundation.interaction.collectIsDraggedAsState
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
@ -33,27 +32,21 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.blankj.utilcode.util.ClipboardUtils
|
import com.blankj.utilcode.util.ClipboardUtils
|
||||||
import com.blankj.utilcode.util.ZipUtils
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import li.songe.gkd.data.RawSubscription
|
import li.songe.gkd.data.RawSubscription
|
||||||
import li.songe.gkd.data.SubsItem
|
import li.songe.gkd.data.SubsItem
|
||||||
import li.songe.gkd.data.TransferData
|
|
||||||
import li.songe.gkd.data.deleteSubscription
|
import li.songe.gkd.data.deleteSubscription
|
||||||
import li.songe.gkd.data.exportTransferData
|
import li.songe.gkd.data.exportData
|
||||||
import li.songe.gkd.ui.destinations.CategoryPageDestination
|
import li.songe.gkd.ui.destinations.CategoryPageDestination
|
||||||
import li.songe.gkd.ui.destinations.GlobalRulePageDestination
|
import li.songe.gkd.ui.destinations.GlobalRulePageDestination
|
||||||
import li.songe.gkd.ui.destinations.SubsPageDestination
|
import li.songe.gkd.ui.destinations.SubsPageDestination
|
||||||
import li.songe.gkd.util.LOCAL_SUBS_ID
|
import li.songe.gkd.util.LOCAL_SUBS_ID
|
||||||
import li.songe.gkd.util.LocalNavController
|
import li.songe.gkd.util.LocalNavController
|
||||||
import li.songe.gkd.util.exportZipDir
|
|
||||||
import li.songe.gkd.util.formatTimeAgo
|
import li.songe.gkd.util.formatTimeAgo
|
||||||
import li.songe.gkd.util.json
|
|
||||||
import li.songe.gkd.util.launchTry
|
import li.songe.gkd.util.launchTry
|
||||||
import li.songe.gkd.util.map
|
import li.songe.gkd.util.map
|
||||||
import li.songe.gkd.util.navigate
|
import li.songe.gkd.util.navigate
|
||||||
import li.songe.gkd.util.openUri
|
import li.songe.gkd.util.openUri
|
||||||
import li.songe.gkd.util.shareFile
|
|
||||||
import li.songe.gkd.util.subsLoadErrorsFlow
|
import li.songe.gkd.util.subsLoadErrorsFlow
|
||||||
import li.songe.gkd.util.subsRefreshErrorsFlow
|
import li.songe.gkd.util.subsRefreshErrorsFlow
|
||||||
import li.songe.gkd.util.subsRefreshingFlow
|
import li.songe.gkd.util.subsRefreshingFlow
|
||||||
|
@ -249,7 +242,7 @@ private fun SubsMenuItem(
|
||||||
onClick = {
|
onClick = {
|
||||||
onExpandedChange(false)
|
onExpandedChange(false)
|
||||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||||
context.shareSubs(subItem.id)
|
exportData(context, listOf(subItem.id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -296,14 +289,3 @@ private fun SubsMenuItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun Context.shareSubs(vararg subsIds: Long) {
|
|
||||||
val transferDataFile = exportZipDir.resolve("${TransferData.TYPE}.json")
|
|
||||||
transferDataFile.writeText(
|
|
||||||
json.encodeToString(exportTransferData(subsIds.toList()))
|
|
||||||
)
|
|
||||||
val file = exportZipDir.resolve("backup-${System.currentTimeMillis()}.zip")
|
|
||||||
ZipUtils.zipFiles(listOf(transferDataFile), file)
|
|
||||||
transferDataFile.delete()
|
|
||||||
this.shareFile(file, "分享数据文件")
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,22 +15,15 @@ import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.blankj.utilcode.util.LogUtils
|
import com.blankj.utilcode.util.LogUtils
|
||||||
import com.blankj.utilcode.util.UriUtils
|
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
import com.ramcosta.composedestinations.annotation.RootNavGraph
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.delay
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import li.songe.gkd.MainActivity
|
import li.songe.gkd.MainActivity
|
||||||
import li.songe.gkd.OpenFileActivity
|
import li.songe.gkd.OpenFileActivity
|
||||||
import li.songe.gkd.OpenSchemeActivity
|
import li.songe.gkd.OpenSchemeActivity
|
||||||
import li.songe.gkd.data.TransferData
|
import li.songe.gkd.data.importData
|
||||||
import li.songe.gkd.data.importTransferData
|
|
||||||
import li.songe.gkd.util.ProfileTransitions
|
import li.songe.gkd.util.ProfileTransitions
|
||||||
import li.songe.gkd.util.checkSubsUpdate
|
|
||||||
import li.songe.gkd.util.json
|
|
||||||
import li.songe.gkd.util.launchTry
|
import li.songe.gkd.util.launchTry
|
||||||
import li.songe.gkd.util.readFileZipByteArray
|
|
||||||
import li.songe.gkd.util.toast
|
import li.songe.gkd.util.toast
|
||||||
|
|
||||||
data class BottomNavItem(
|
data class BottomNavItem(
|
||||||
|
@ -53,8 +46,7 @@ fun HomePage() {
|
||||||
|
|
||||||
val pages = arrayOf(controlPage, subsPage, appListPage, settingsPage)
|
val pages = arrayOf(controlPage, subsPage, appListPage, settingsPage)
|
||||||
|
|
||||||
val currentPage = pages.find { p -> p.navItem.label == tab.label }
|
val currentPage = pages.find { p -> p.navItem.label == tab.label } ?: controlPage
|
||||||
?: controlPage
|
|
||||||
|
|
||||||
val intent = context.intent
|
val intent = context.intent
|
||||||
LaunchedEffect(key1 = intent, block = {
|
LaunchedEffect(key1 = intent, block = {
|
||||||
|
@ -67,23 +59,7 @@ fun HomePage() {
|
||||||
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
vm.viewModelScope.launchTry(Dispatchers.IO) {
|
||||||
toast("加载导入...")
|
toast("加载导入...")
|
||||||
vm.tabFlow.value = subsPage.navItem
|
vm.tabFlow.value = subsPage.navItem
|
||||||
val string = readFileZipByteArray(
|
importData(uri)
|
||||||
UriUtils.uri2Bytes(uri),
|
|
||||||
"${TransferData.TYPE}.json"
|
|
||||||
)
|
|
||||||
if (string != null) {
|
|
||||||
val transferData = withContext(Dispatchers.Default) {
|
|
||||||
json.decodeFromString<TransferData>(string)
|
|
||||||
}
|
|
||||||
val hasNewSubsItem = importTransferData(transferData)
|
|
||||||
toast("导入成功")
|
|
||||||
if (hasNewSubsItem) {
|
|
||||||
delay(1000)
|
|
||||||
checkSubsUpdate(true)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
toast("导入失败")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (source == OpenSchemeActivity::class.qualifiedName) {
|
} else if (source == OpenSchemeActivity::class.qualifiedName) {
|
||||||
LogUtils.d(uri)
|
LogUtils.d(uri)
|
||||||
|
@ -97,8 +73,7 @@ fun HomePage() {
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
NavigationBar {
|
NavigationBar {
|
||||||
pages.forEach { page ->
|
pages.forEach { page ->
|
||||||
NavigationBarItem(
|
NavigationBarItem(selected = tab.label == page.navItem.label,
|
||||||
selected = tab.label == page.navItem.label,
|
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
onClick = {
|
onClick = {
|
||||||
vm.tabFlow.value = page.navItem
|
vm.tabFlow.value = page.navItem
|
||||||
|
@ -111,8 +86,7 @@ fun HomePage() {
|
||||||
},
|
},
|
||||||
label = {
|
label = {
|
||||||
Text(text = page.navItem.label)
|
Text(text = page.navItem.label)
|
||||||
}
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -53,27 +53,23 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.blankj.utilcode.util.UriUtils
|
|
||||||
import com.dylanc.activityresult.launcher.launchForResult
|
import com.dylanc.activityresult.launcher.launchForResult
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import li.songe.gkd.data.TransferData
|
|
||||||
import li.songe.gkd.data.Value
|
import li.songe.gkd.data.Value
|
||||||
import li.songe.gkd.data.deleteSubscription
|
import li.songe.gkd.data.deleteSubscription
|
||||||
import li.songe.gkd.data.importTransferData
|
import li.songe.gkd.data.exportData
|
||||||
|
import li.songe.gkd.data.importData
|
||||||
import li.songe.gkd.db.DbSet
|
import li.songe.gkd.db.DbSet
|
||||||
import li.songe.gkd.ui.component.SubsItemCard
|
import li.songe.gkd.ui.component.SubsItemCard
|
||||||
import li.songe.gkd.ui.component.getDialogResult
|
import li.songe.gkd.ui.component.getDialogResult
|
||||||
import li.songe.gkd.ui.component.shareSubs
|
|
||||||
import li.songe.gkd.util.LOCAL_SUBS_ID
|
import li.songe.gkd.util.LOCAL_SUBS_ID
|
||||||
import li.songe.gkd.util.LocalLauncher
|
import li.songe.gkd.util.LocalLauncher
|
||||||
import li.songe.gkd.util.checkSubsUpdate
|
import li.songe.gkd.util.checkSubsUpdate
|
||||||
import li.songe.gkd.util.isSafeUrl
|
import li.songe.gkd.util.isSafeUrl
|
||||||
import li.songe.gkd.util.json
|
|
||||||
import li.songe.gkd.util.launchAsFn
|
import li.songe.gkd.util.launchAsFn
|
||||||
import li.songe.gkd.util.launchTry
|
import li.songe.gkd.util.launchTry
|
||||||
import li.songe.gkd.util.readFileZipByteArray
|
|
||||||
import li.songe.gkd.util.subsIdToRawFlow
|
import li.songe.gkd.util.subsIdToRawFlow
|
||||||
import li.songe.gkd.util.subsItemsFlow
|
import li.songe.gkd.util.subsItemsFlow
|
||||||
import li.songe.gkd.util.subsRefreshingFlow
|
import li.songe.gkd.util.subsRefreshingFlow
|
||||||
|
@ -225,7 +221,7 @@ fun useSubsManagePage(): ScaffoldExt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IconButton(onClick = vm.viewModelScope.launchAsFn(Dispatchers.IO) {
|
IconButton(onClick = vm.viewModelScope.launchAsFn(Dispatchers.IO) {
|
||||||
context.shareSubs(*selectedIds.toLongArray())
|
exportData(context, selectedIds)
|
||||||
}) {
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Share,
|
imageVector = Icons.Default.Share,
|
||||||
|
@ -305,17 +301,7 @@ fun useSubsManagePage(): ScaffoldExt {
|
||||||
toast("未选择文件")
|
toast("未选择文件")
|
||||||
return@launchAsFn
|
return@launchAsFn
|
||||||
}
|
}
|
||||||
val string = readFileZipByteArray(
|
importData(uri)
|
||||||
UriUtils.uri2Bytes(uri), "${TransferData.TYPE}.json"
|
|
||||||
)
|
|
||||||
if (string != null) {
|
|
||||||
val transferData =
|
|
||||||
json.decodeFromString<TransferData>(string)
|
|
||||||
importTransferData(transferData)
|
|
||||||
toast("导入成功")
|
|
||||||
} else {
|
|
||||||
toast("导入文件无数据")
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ val newVersionApkDir by lazy { cacheDir.resolve("newVersionApk") }
|
||||||
val logZipDir by lazy { cacheDir.resolve("logZip") }
|
val logZipDir by lazy { cacheDir.resolve("logZip") }
|
||||||
val imageCacheDir by lazy { cacheDir.resolve("imageCache") }
|
val imageCacheDir by lazy { cacheDir.resolve("imageCache") }
|
||||||
val exportZipDir by lazy { cacheDir.resolve("exportZip") }
|
val exportZipDir by lazy { cacheDir.resolve("exportZip") }
|
||||||
|
val importZipDir by lazy { cacheDir.resolve("exportZip") }
|
||||||
|
|
||||||
fun initFolder() {
|
fun initFolder() {
|
||||||
listOf(
|
listOf(
|
||||||
|
@ -31,7 +32,8 @@ fun initFolder() {
|
||||||
newVersionApkDir,
|
newVersionApkDir,
|
||||||
logZipDir,
|
logZipDir,
|
||||||
imageCacheDir,
|
imageCacheDir,
|
||||||
exportZipDir
|
exportZipDir,
|
||||||
|
importZipDir
|
||||||
).forEach { f ->
|
).forEach { f ->
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
// TODO 在某些机型上无法创建目录 用户反馈重启手机后解决 是否存在其它解决方式?
|
// TODO 在某些机型上无法创建目录 用户反馈重启手机后解决 是否存在其它解决方式?
|
||||||
|
@ -46,18 +48,27 @@ fun clearCache() {
|
||||||
newVersionApkDir,
|
newVersionApkDir,
|
||||||
logZipDir,
|
logZipDir,
|
||||||
imageCacheDir,
|
imageCacheDir,
|
||||||
exportZipDir
|
exportZipDir,
|
||||||
|
importZipDir
|
||||||
).forEach { dir ->
|
).forEach { dir ->
|
||||||
if (dir.isDirectory && dir.exists()) {
|
if (dir.isDirectory && dir.exists()) {
|
||||||
dir.listFiles()?.forEach { file ->
|
dir.deleteRecursively()
|
||||||
if (file.isFile) {
|
dir.mkdir()
|
||||||
file.delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun File.resetDirectory() {
|
||||||
|
if (isFile) {
|
||||||
|
delete()
|
||||||
|
} else if (isDirectory) {
|
||||||
|
deleteRecursively()
|
||||||
|
}
|
||||||
|
if (!exists()) {
|
||||||
|
mkdir()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun buildLogFile(): File {
|
fun buildLogFile(): File {
|
||||||
val files = mutableListOf(dbFolder, subsFolder)
|
val files = mutableListOf(dbFolder, subsFolder)
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
package li.songe.gkd.util
|
|
||||||
|
|
||||||
import java.io.BufferedReader
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.InputStreamReader
|
|
||||||
import java.util.zip.ZipEntry
|
|
||||||
import java.util.zip.ZipInputStream
|
|
||||||
|
|
||||||
fun readFileZipByteArray(zipByteArray: ByteArray, fileName: String): String? {
|
|
||||||
val byteArrayInputStream = ByteArrayInputStream(zipByteArray)
|
|
||||||
val zipInputStream = ZipInputStream(byteArrayInputStream)
|
|
||||||
zipInputStream.use {
|
|
||||||
var zipEntry: ZipEntry? = zipInputStream.nextEntry
|
|
||||||
while (zipEntry != null) {
|
|
||||||
if (zipEntry.name == fileName) {
|
|
||||||
val reader = BufferedReader(InputStreamReader(zipInputStream))
|
|
||||||
val content = reader.use { it.readText() }
|
|
||||||
return content
|
|
||||||
}
|
|
||||||
zipEntry = zipInputStream.nextEntry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user