diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
index 6abdbc4f..963e1c11 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Settings.kt
@@ -9,10 +9,27 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.*
-import androidx.compose.material3.*
-import androidx.compose.runtime.*
+import androidx.compose.material.icons.filled.ArrowBack
+import androidx.compose.material.icons.filled.BugReport
+import androidx.compose.material.icons.filled.Compress
+import androidx.compose.material.icons.filled.ContactPage
+import androidx.compose.material.icons.filled.DeveloperMode
+import androidx.compose.material.icons.filled.Fence
+import androidx.compose.material.icons.filled.RemoveModerator
+import androidx.compose.material.icons.filled.Update
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.ListItem
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@@ -28,11 +45,14 @@ import me.weishu.kernelsu.BuildConfig
import me.weishu.kernelsu.Natives
import me.weishu.kernelsu.R
import me.weishu.kernelsu.ui.component.AboutDialog
+import me.weishu.kernelsu.ui.component.ConfirmResult
import me.weishu.kernelsu.ui.component.SwitchItem
+import me.weishu.kernelsu.ui.component.rememberConfirmDialog
import me.weishu.kernelsu.ui.component.rememberCustomDialog
import me.weishu.kernelsu.ui.component.rememberLoadingDialog
import me.weishu.kernelsu.ui.screen.destinations.AppProfileTemplateScreenDestination
import me.weishu.kernelsu.ui.util.getBugreportFile
+import me.weishu.kernelsu.ui.util.shrinkModules
/**
* @author weishu
@@ -52,6 +72,7 @@ fun SettingScreen(navigator: DestinationsNavigator) {
AboutDialog(it)
}
val loadingDialog = rememberLoadingDialog()
+ val shrinkDialog = rememberConfirmDialog()
Column(
modifier = Modifier
@@ -156,6 +177,29 @@ fun SettingScreen(navigator: DestinationsNavigator) {
}
)
+ val shrink = stringResource(id = R.string.shrink_sparse_image)
+ val shrinkMessage = stringResource(id = R.string.shrink_sparse_image_message)
+ ListItem(
+ leadingContent = {
+ Icon(
+ Icons.Filled.Compress,
+ shrink
+ )
+ },
+ headlineContent = { Text(shrink) },
+ modifier = Modifier.clickable {
+ scope.launch {
+ val result =
+ shrinkDialog.awaitConfirm(title = shrink, content = shrinkMessage)
+ if (result == ConfirmResult.Confirmed) {
+ loadingDialog.withLoading {
+ shrinkModules()
+ }
+ }
+ }
+ }
+ )
+
val about = stringResource(id = R.string.about)
ListItem(
leadingContent = {
diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
index 9c1ce554..709d20af 100644
--- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
+++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt
@@ -56,8 +56,8 @@ fun createRootShell(globalMnt: Boolean = false): Shell {
}
}
-fun execKsud(args: String): Boolean {
- val shell = getRootShell()
+fun execKsud(args: String, newShell: Boolean = false): Boolean {
+ val shell = if (newShell) createRootShell() else getRootShell()
return ShellUtils.fastCmdResult(shell, "${getKsuDaemonPath()} $args")
}
@@ -142,6 +142,10 @@ fun installModule(
}
}
+suspend fun shrinkModules(): Boolean = withContext(Dispatchers.IO) {
+ execKsud("module shrink", true)
+}
+
@Parcelize
sealed class LkmSelection : Parcelable {
data class LkmUri(val uri: Uri) : LkmSelection()
diff --git a/manager/app/src/main/res/values-zh-rCN/strings.xml b/manager/app/src/main/res/values-zh-rCN/strings.xml
index d50b46d8..6d6b3c6e 100644
--- a/manager/app/src/main/res/values-zh-rCN/strings.xml
+++ b/manager/app/src/main/res/values-zh-rCN/strings.xml
@@ -115,4 +115,6 @@
下一步
建议选择 %1$s 分区镜像
选择 KMI
+ 最小化稀疏文件
+ 将模块所在的稀疏文件镜像调整为其实际大小,注意这可能导致模块工作异常,请仅在必要时(如备份)使用。
\ No newline at end of file
diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml
index 53c105b6..2cb48b3a 100644
--- a/manager/app/src/main/res/values/strings.xml
+++ b/manager/app/src/main/res/values/strings.xml
@@ -117,4 +117,6 @@
Next
%1$s partition image is recommended
Select KMI
+ Minimize sparse image
+ Adjust the sparse file mirror where the module is located to its actual size. Note that this may cause the module to function abnormally, please only use when necessary (such as for backup)