manager: support meta module (#616)
This commit is contained in:
@@ -33,6 +33,8 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.compose.material.icons.outlined.Info
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
import com.ramcosta.composedestinations.annotation.Destination
|
import com.ramcosta.composedestinations.annotation.Destination
|
||||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||||
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
|
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
|
||||||
@@ -52,8 +54,10 @@ import java.io.File
|
|||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
|
import com.sukisu.ultra.ui.component.rememberCustomDialog
|
||||||
import com.sukisu.ultra.ui.util.module.ModuleOperationUtils
|
import com.sukisu.ultra.ui.util.module.ModuleOperationUtils
|
||||||
import com.sukisu.ultra.ui.util.module.ModuleUtils
|
import com.sukisu.ultra.ui.util.module.ModuleUtils
|
||||||
|
import com.topjohnwu.superuser.io.SuFile
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ShirkNeko
|
* @author ShirkNeko
|
||||||
@@ -152,6 +156,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
var tempText: String
|
var tempText: String
|
||||||
val logContent = rememberSaveable { StringBuilder() }
|
val logContent = rememberSaveable { StringBuilder() }
|
||||||
var showFloatAction by rememberSaveable { mutableStateOf(false) }
|
var showFloatAction by rememberSaveable { mutableStateOf(false) }
|
||||||
|
var shouldWarningUserMetaModule by rememberSaveable { mutableStateOf(false) }
|
||||||
// 添加状态跟踪是否已经完成刷写
|
// 添加状态跟踪是否已经完成刷写
|
||||||
var hasFlashCompleted by rememberSaveable { mutableStateOf(false) }
|
var hasFlashCompleted by rememberSaveable { mutableStateOf(false) }
|
||||||
var hasExecuted by rememberSaveable { mutableStateOf(false) }
|
var hasExecuted by rememberSaveable { mutableStateOf(false) }
|
||||||
@@ -170,6 +175,39 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
val logSavedString = stringResource(R.string.log_saved)
|
val logSavedString = stringResource(R.string.log_saved)
|
||||||
val installingModuleString = stringResource(R.string.installing_module)
|
val installingModuleString = stringResource(R.string.installing_module)
|
||||||
|
|
||||||
|
val alertDialog = rememberCustomDialog { dismiss: () -> Unit ->
|
||||||
|
val uriHandler = LocalUriHandler.current
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = { dismiss() },
|
||||||
|
icon = {
|
||||||
|
Icon(Icons.Outlined.Info, contentDescription = null)
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
Row(modifier = Modifier
|
||||||
|
.fillMaxWidth(),
|
||||||
|
horizontalArrangement = Arrangement.Center
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(R.string.warning_of_meta_module_title))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(text = stringResource(R.string.warning_of_meta_module_summary))
|
||||||
|
},
|
||||||
|
confirmButton = {
|
||||||
|
FilledTonalButton(onClick = { dismiss() }) {
|
||||||
|
Text(text = stringResource(id = android.R.string.ok))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissButton = {
|
||||||
|
OutlinedButton(onClick = {
|
||||||
|
uriHandler.openUri("https://kernelsu.org/guide/metamodule.html")
|
||||||
|
}) {
|
||||||
|
Text(text = stringResource(id = R.string.learn_more))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 当前模块安装状态
|
// 当前模块安装状态
|
||||||
val currentStatus = moduleInstallStatus.value
|
val currentStatus = moduleInstallStatus.value
|
||||||
|
|
||||||
@@ -182,16 +220,19 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
totalModules = flashIt.uris.size,
|
totalModules = flashIt.uris.size,
|
||||||
currentModule = 1
|
currentModule = 1
|
||||||
)
|
)
|
||||||
|
shouldWarningUserMetaModule = false
|
||||||
hasFlashCompleted = false
|
hasFlashCompleted = false
|
||||||
hasExecuted = false
|
hasExecuted = false
|
||||||
moduleVerificationMap.clear()
|
moduleVerificationMap.clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is FlashIt.FlashModuleUpdate -> {
|
is FlashIt.FlashModuleUpdate -> {
|
||||||
|
shouldWarningUserMetaModule = false
|
||||||
hasUpdateCompleted = false
|
hasUpdateCompleted = false
|
||||||
hasUpdateExecuted = false
|
hasUpdateExecuted = false
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
shouldWarningUserMetaModule = false
|
||||||
hasFlashCompleted = false
|
hasFlashCompleted = false
|
||||||
hasExecuted = false
|
hasExecuted = false
|
||||||
}
|
}
|
||||||
@@ -240,10 +281,29 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
}
|
}
|
||||||
hasUpdateCompleted = true
|
hasUpdateCompleted = true
|
||||||
|
|
||||||
|
if (!hasMetaModule() && code == 0) {
|
||||||
|
// 如果没安装 MetaModule,且此模块需要挂载,并且当前模块安装成功,警告用户
|
||||||
|
scope.launch {
|
||||||
|
val mountOldDirectory = SuFile.open("/data/adb/modules/${getModuleIdFromUri(context,flashIt.uri)}/system")
|
||||||
|
val mountNewDirectory = SuFile.open("/data/adb/modules_update/${getModuleIdFromUri(context,flashIt.uri)}/system")
|
||||||
|
if (!(mountNewDirectory.isDirectory) && !(mountOldDirectory.isDirectory)) return@launch
|
||||||
|
shouldWarningUserMetaModule = true
|
||||||
|
|
||||||
|
alertDialog.show()
|
||||||
|
shouldWarningUserMetaModule = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 如果是外部安装或需要自动退出的模块更新且不需要重启,延迟后自动返回
|
// 如果是外部安装或需要自动退出的模块更新且不需要重启,延迟后自动返回
|
||||||
if (isExternalInstall || shouldAutoExit) {
|
if (isExternalInstall || shouldAutoExit) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
while (shouldWarningUserMetaModule) {
|
||||||
|
kotlinx.coroutines.delay(100)
|
||||||
|
}
|
||||||
kotlinx.coroutines.delay(1000)
|
kotlinx.coroutines.delay(1000)
|
||||||
|
while (shouldWarningUserMetaModule) {
|
||||||
|
kotlinx.coroutines.delay(100)
|
||||||
|
}
|
||||||
if (shouldAutoExit) {
|
if (shouldAutoExit) {
|
||||||
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
sharedPref.edit { remove("auto_exit_after_flash") }
|
sharedPref.edit { remove("auto_exit_after_flash") }
|
||||||
@@ -334,6 +394,38 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasFlashCompleted = true
|
hasFlashCompleted = true
|
||||||
|
if (!hasMetaModule() && code == 0) {
|
||||||
|
// 没有 MetaModule,且安装成功,检查此模块是否有自动挂载
|
||||||
|
scope.launch {
|
||||||
|
var mountOldDirectory : File
|
||||||
|
var mountNewDirectory : File
|
||||||
|
when (flashIt) {
|
||||||
|
is FlashIt.FlashModules -> {
|
||||||
|
mountOldDirectory = SuFile.open("/data/adb/modules/${getModuleIdFromUri(context,flashIt.uris[flashIt.currentIndex])}/system")
|
||||||
|
mountNewDirectory = SuFile.open("/data/adb/modules_update/${getModuleIdFromUri(context,flashIt.uris[flashIt.currentIndex])}/system")
|
||||||
|
}
|
||||||
|
|
||||||
|
is FlashIt.FlashModule -> {
|
||||||
|
mountOldDirectory = SuFile.open("/data/adb/modules/${getModuleIdFromUri(context,flashIt.uri)}/system")
|
||||||
|
mountNewDirectory = SuFile.open("/data/adb/modules_update/${getModuleIdFromUri(context,flashIt.uri)}/system")
|
||||||
|
}
|
||||||
|
|
||||||
|
is FlashIt.FlashModuleUpdate -> {
|
||||||
|
mountOldDirectory = SuFile.open("/data/adb/modules/${getModuleIdFromUri(context,flashIt.uri)}/system")
|
||||||
|
mountNewDirectory = SuFile.open("/data/adb/modules_update/${getModuleIdFromUri(context,flashIt.uri)}/system")
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> return@launch
|
||||||
|
}
|
||||||
|
if (!mountNewDirectory.isDirectory && !mountOldDirectory.isDirectory) return@launch
|
||||||
|
shouldWarningUserMetaModule = true
|
||||||
|
|
||||||
|
if (!hasMetaModule() && (flashIt !is FlashIt.FlashModules || flashIt.currentIndex >= flashIt.uris.size - 1)) {
|
||||||
|
// 如果没有 MetaModule,且当前不是多模块刷写或是最后一个需要自动刷写的模块,而且有模块需要挂载,警告用户
|
||||||
|
alertDialog.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (flashIt is FlashIt.FlashModules && flashIt.currentIndex < flashIt.uris.size - 1) {
|
if (flashIt is FlashIt.FlashModules && flashIt.currentIndex < flashIt.uris.size - 1) {
|
||||||
val nextFlashIt = flashIt.copy(
|
val nextFlashIt = flashIt.copy(
|
||||||
@@ -346,7 +438,13 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
} else if ((isExternalInstall || shouldAutoExit) && flashIt is FlashIt.FlashModules && flashIt.currentIndex >= flashIt.uris.size - 1) {
|
} else if ((isExternalInstall || shouldAutoExit) && flashIt is FlashIt.FlashModules && flashIt.currentIndex >= flashIt.uris.size - 1) {
|
||||||
// 如果是外部安装或需要自动退出且是最后一个模块,安装完成后自动返回
|
// 如果是外部安装或需要自动退出且是最后一个模块,安装完成后自动返回
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
while (shouldWarningUserMetaModule) {
|
||||||
|
kotlinx.coroutines.delay(100)
|
||||||
|
}
|
||||||
kotlinx.coroutines.delay(1000)
|
kotlinx.coroutines.delay(1000)
|
||||||
|
while (shouldWarningUserMetaModule) {
|
||||||
|
kotlinx.coroutines.delay(100)
|
||||||
|
}
|
||||||
if (shouldAutoExit) {
|
if (shouldAutoExit) {
|
||||||
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
sharedPref.edit { remove("auto_exit_after_flash") }
|
sharedPref.edit { remove("auto_exit_after_flash") }
|
||||||
@@ -356,7 +454,13 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) {
|
|||||||
} else if ((isExternalInstall || shouldAutoExit) && flashIt is FlashIt.FlashModule) {
|
} else if ((isExternalInstall || shouldAutoExit) && flashIt is FlashIt.FlashModule) {
|
||||||
// 如果是外部安装或需要自动退出的单个模块,安装完成后自动返回
|
// 如果是外部安装或需要自动退出的单个模块,安装完成后自动返回
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
while (shouldWarningUserMetaModule) {
|
||||||
|
kotlinx.coroutines.delay(100)
|
||||||
|
}
|
||||||
kotlinx.coroutines.delay(1000)
|
kotlinx.coroutines.delay(1000)
|
||||||
|
while (shouldWarningUserMetaModule) {
|
||||||
|
kotlinx.coroutines.delay(100)
|
||||||
|
}
|
||||||
if (shouldAutoExit) {
|
if (shouldAutoExit) {
|
||||||
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
val sharedPref = context.getSharedPreferences("kernel_flash_prefs", Context.MODE_PRIVATE)
|
||||||
sharedPref.edit { remove("auto_exit_after_flash") }
|
sharedPref.edit { remove("auto_exit_after_flash") }
|
||||||
@@ -705,6 +809,22 @@ suspend fun getModuleNameFromUri(context: Context, uri: Uri): String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getModuleIdFromUri(context: Context, uri: Uri): String? {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
if (uri == Uri.EMPTY) {
|
||||||
|
return@withContext null
|
||||||
|
}
|
||||||
|
if (!ModuleUtils.isUriAccessible(context, uri)) {
|
||||||
|
return@withContext null
|
||||||
|
}
|
||||||
|
ModuleUtils.extractModuleId(context, uri)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
sealed class FlashIt : Parcelable {
|
sealed class FlashIt : Parcelable {
|
||||||
data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean, val partition: String? = null) : FlashIt()
|
data class FlashBoot(val boot: Uri? = null, val lkm: LkmSelection, val ota: Boolean, val partition: String? = null) : FlashIt()
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ fun HomeScreen(navigator: DestinationsNavigator) {
|
|||||||
isSimpleMode = viewModel.isSimpleMode,
|
isSimpleMode = viewModel.isSimpleMode,
|
||||||
isHideSusfsStatus = viewModel.isHideSusfsStatus,
|
isHideSusfsStatus = viewModel.isHideSusfsStatus,
|
||||||
isHideZygiskImplement = viewModel.isHideZygiskImplement,
|
isHideZygiskImplement = viewModel.isHideZygiskImplement,
|
||||||
|
isHideMetaModuleImplement = viewModel.isHideMetaModuleImplement,
|
||||||
showKpmInfo = viewModel.showKpmInfo,
|
showKpmInfo = viewModel.showKpmInfo,
|
||||||
lkmMode = viewModel.systemStatus.lkmMode,
|
lkmMode = viewModel.systemStatus.lkmMode,
|
||||||
)
|
)
|
||||||
@@ -652,6 +653,7 @@ private fun InfoCard(
|
|||||||
isSimpleMode: Boolean,
|
isSimpleMode: Boolean,
|
||||||
isHideSusfsStatus: Boolean,
|
isHideSusfsStatus: Boolean,
|
||||||
isHideZygiskImplement: Boolean,
|
isHideZygiskImplement: Boolean,
|
||||||
|
isHideMetaModuleImplement: Boolean,
|
||||||
showKpmInfo: Boolean,
|
showKpmInfo: Boolean,
|
||||||
lkmMode: Boolean?
|
lkmMode: Boolean?
|
||||||
) {
|
) {
|
||||||
@@ -784,6 +786,14 @@ private fun InfoCard(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isHideMetaModuleImplement && !isSimpleMode && systemInfo.metaModuleImplement != "None") {
|
||||||
|
InfoCardItem(
|
||||||
|
stringResource(R.string.home_meta_module_implement),
|
||||||
|
systemInfo.metaModuleImplement,
|
||||||
|
icon = Icons.Default.Extension,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (!isSimpleMode) {
|
if (!isSimpleMode) {
|
||||||
if (lkmMode != true && !showKpmInfo) {
|
if (lkmMode != true && !showKpmInfo) {
|
||||||
val displayVersion =
|
val displayVersion =
|
||||||
|
|||||||
@@ -752,6 +752,7 @@ private fun ModuleList(
|
|||||||
val uninstall = stringResource(R.string.uninstall)
|
val uninstall = stringResource(R.string.uninstall)
|
||||||
val cancel = stringResource(android.R.string.cancel)
|
val cancel = stringResource(android.R.string.cancel)
|
||||||
val moduleUninstallConfirm = stringResource(R.string.module_uninstall_confirm)
|
val moduleUninstallConfirm = stringResource(R.string.module_uninstall_confirm)
|
||||||
|
val metaModuleUninstallConfirm = stringResource(R.string.metamodule_uninstall_confirm)
|
||||||
val updateText = stringResource(R.string.module_update)
|
val updateText = stringResource(R.string.module_update)
|
||||||
val changelogText = stringResource(R.string.module_changelog)
|
val changelogText = stringResource(R.string.module_changelog)
|
||||||
val downloadingText = stringResource(R.string.module_downloading)
|
val downloadingText = stringResource(R.string.module_downloading)
|
||||||
@@ -847,9 +848,10 @@ private fun ModuleList(
|
|||||||
suspend fun onModuleUninstallClicked(module: ModuleViewModel.ModuleInfo) {
|
suspend fun onModuleUninstallClicked(module: ModuleViewModel.ModuleInfo) {
|
||||||
val isUninstall = !module.remove
|
val isUninstall = !module.remove
|
||||||
if (isUninstall) {
|
if (isUninstall) {
|
||||||
|
val formatter = if (module.metamodule) metaModuleUninstallConfirm else moduleUninstallConfirm
|
||||||
val confirmResult = confirmDialog.awaitConfirm(
|
val confirmResult = confirmDialog.awaitConfirm(
|
||||||
moduleStr,
|
moduleStr,
|
||||||
content = moduleUninstallConfirm.format(module.name),
|
content = formatter.format(module.name),
|
||||||
confirm = uninstall,
|
confirm = uninstall,
|
||||||
dismiss = cancel
|
dismiss = cancel
|
||||||
)
|
)
|
||||||
@@ -1199,6 +1201,22 @@ fun ModuleItem(
|
|||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
) {
|
) {
|
||||||
|
if (module.metamodule) {
|
||||||
|
Surface(
|
||||||
|
shape = RoundedCornerShape(4.dp),
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "META",
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
modifier = Modifier.padding(horizontal = 4.dp, vertical = 1.dp),
|
||||||
|
color = MaterialTheme.colorScheme.onPrimary,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Surface(
|
Surface(
|
||||||
shape = RoundedCornerShape(4.dp),
|
shape = RoundedCornerShape(4.dp),
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
@@ -1329,8 +1347,9 @@ fun ModuleItemPreview() {
|
|||||||
update = true,
|
update = true,
|
||||||
remove = false,
|
remove = false,
|
||||||
updateJson = "",
|
updateJson = "",
|
||||||
hasWebUi = false,
|
hasWebUi = true,
|
||||||
hasActionScript = false,
|
hasActionScript = true,
|
||||||
|
metamodule = true,
|
||||||
dirId = "dirId",
|
dirId = "dirId",
|
||||||
config = ModuleConfig(),
|
config = ModuleConfig(),
|
||||||
isVerified = true,
|
isVerified = true,
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ import kotlinx.parcelize.Parcelize
|
|||||||
import com.sukisu.ultra.BuildConfig
|
import com.sukisu.ultra.BuildConfig
|
||||||
import com.sukisu.ultra.Natives
|
import com.sukisu.ultra.Natives
|
||||||
import com.sukisu.ultra.ksuApp
|
import com.sukisu.ultra.ksuApp
|
||||||
|
import com.topjohnwu.superuser.io.SuFile
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.Properties
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,6 +113,10 @@ fun install() {
|
|||||||
Log.w(TAG, "install result: $result, cost: ${SystemClock.elapsedRealtime() - start}ms")
|
Log.w(TAG, "install result: $result, cost: ${SystemClock.elapsedRealtime() - start}ms")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hasMetaModule(): Boolean {
|
||||||
|
return getMetaModuleImplement() != "None"
|
||||||
|
}
|
||||||
|
|
||||||
fun listModules(): String {
|
fun listModules(): String {
|
||||||
val shell = getRootShell()
|
val shell = getRootShell()
|
||||||
|
|
||||||
@@ -575,6 +581,26 @@ fun getSuSFSFeatures(): String {
|
|||||||
return runCmd(shell, cmd)
|
return runCmd(shell, cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getMetaModuleImplement(): String {
|
||||||
|
try {
|
||||||
|
val metaModuleProp = SuFile.open("/data/adb/metamodule/module.prop")
|
||||||
|
if (!metaModuleProp.isFile) {
|
||||||
|
Log.i(TAG, "Meta module implement: None")
|
||||||
|
return "None"
|
||||||
|
}
|
||||||
|
|
||||||
|
val prop = Properties()
|
||||||
|
prop.load(metaModuleProp.newInputStream())
|
||||||
|
|
||||||
|
val name = prop.getProperty("name")
|
||||||
|
Log.i(TAG, "Meta module implement: $name")
|
||||||
|
return name
|
||||||
|
} catch (t : Throwable) {
|
||||||
|
Log.i(TAG, "Meta module implement: None")
|
||||||
|
return "None"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun getZygiskImplement(): String {
|
fun getZygiskImplement(): String {
|
||||||
val zygiskModuleIds = listOf(
|
val zygiskModuleIds = listOf(
|
||||||
"zygisksu",
|
"zygisksu",
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ class HomeViewModel : ViewModel() {
|
|||||||
val kpmModuleCount: Int = 0,
|
val kpmModuleCount: Int = 0,
|
||||||
val managersList: Natives.ManagersList? = null,
|
val managersList: Natives.ManagersList? = null,
|
||||||
val isDynamicSignEnabled: Boolean = false,
|
val isDynamicSignEnabled: Boolean = false,
|
||||||
val zygiskImplement: String = ""
|
val zygiskImplement: String = "",
|
||||||
|
val metaModuleImplement: String = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
// 状态变量
|
// 状态变量
|
||||||
@@ -79,6 +80,8 @@ class HomeViewModel : ViewModel() {
|
|||||||
private set
|
private set
|
||||||
var isHideZygiskImplement by mutableStateOf(false)
|
var isHideZygiskImplement by mutableStateOf(false)
|
||||||
private set
|
private set
|
||||||
|
var isHideMetaModuleImplement by mutableStateOf(false)
|
||||||
|
private set
|
||||||
var isHideLinkCard by mutableStateOf(false)
|
var isHideLinkCard by mutableStateOf(false)
|
||||||
private set
|
private set
|
||||||
var showKpmInfo by mutableStateOf(false)
|
var showKpmInfo by mutableStateOf(false)
|
||||||
@@ -109,6 +112,7 @@ class HomeViewModel : ViewModel() {
|
|||||||
isHideSusfsStatus = settingsPrefs.getBoolean("is_hide_susfs_status", false)
|
isHideSusfsStatus = settingsPrefs.getBoolean("is_hide_susfs_status", false)
|
||||||
isHideLinkCard = settingsPrefs.getBoolean("is_hide_link_card", false)
|
isHideLinkCard = settingsPrefs.getBoolean("is_hide_link_card", false)
|
||||||
isHideZygiskImplement = settingsPrefs.getBoolean("is_hide_zygisk_Implement", false)
|
isHideZygiskImplement = settingsPrefs.getBoolean("is_hide_zygisk_Implement", false)
|
||||||
|
isHideMetaModuleImplement = settingsPrefs.getBoolean("is_hide_meta_module_Implement", false)
|
||||||
showKpmInfo = settingsPrefs.getBoolean("show_kpm_info", false)
|
showKpmInfo = settingsPrefs.getBoolean("show_kpm_info", false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +226,8 @@ class HomeViewModel : ViewModel() {
|
|||||||
superuserCount = moduleInfo.second,
|
superuserCount = moduleInfo.second,
|
||||||
moduleCount = moduleInfo.third,
|
moduleCount = moduleInfo.third,
|
||||||
kpmModuleCount = moduleInfo.fourth,
|
kpmModuleCount = moduleInfo.fourth,
|
||||||
zygiskImplement = moduleInfo.fifth
|
zygiskImplement = moduleInfo.fifth,
|
||||||
|
metaModuleImplement = moduleInfo.sixth
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,7 +403,7 @@ class HomeViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun loadModuleInfo(): Tuple5<String, Int, Int, Int, String> {
|
private suspend fun loadModuleInfo(): Tuple6<String, Int, Int, Int, String, String> {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val kpmVersion = try {
|
val kpmVersion = try {
|
||||||
getKpmVersion()
|
getKpmVersion()
|
||||||
@@ -430,7 +435,13 @@ class HomeViewModel : ViewModel() {
|
|||||||
"None"
|
"None"
|
||||||
}
|
}
|
||||||
|
|
||||||
Tuple5(kpmVersion, superuserCount, moduleCount, kpmModuleCount, zygiskImplement)
|
val metaModuleImplement = try {
|
||||||
|
getMetaModuleImplement()
|
||||||
|
} catch (_: Exception) {
|
||||||
|
"None"
|
||||||
|
}
|
||||||
|
|
||||||
|
Tuple6(kpmVersion, superuserCount, moduleCount, kpmModuleCount, zygiskImplement, metaModuleImplement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,6 +578,15 @@ class HomeViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class Tuple6<T1, T2, T3, T4, T5, T6>(
|
||||||
|
val first: T1,
|
||||||
|
val second: T2,
|
||||||
|
val third: T3,
|
||||||
|
val fourth: T4,
|
||||||
|
val fifth: T5,
|
||||||
|
val sixth: T6
|
||||||
|
)
|
||||||
|
|
||||||
data class Tuple5<T1, T2, T3, T4, T5>(
|
data class Tuple5<T1, T2, T3, T4, T5>(
|
||||||
val first: T1,
|
val first: T1,
|
||||||
val second: T2,
|
val second: T2,
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ class ModuleViewModel : ViewModel() {
|
|||||||
val updateJson: String,
|
val updateJson: String,
|
||||||
val hasWebUi: Boolean,
|
val hasWebUi: Boolean,
|
||||||
val hasActionScript: Boolean,
|
val hasActionScript: Boolean,
|
||||||
|
val metamodule: Boolean,
|
||||||
val dirId: String, // real module id (dir name)
|
val dirId: String, // real module id (dir name)
|
||||||
var config: ModuleConfig? = null,
|
var config: ModuleConfig? = null,
|
||||||
var isVerified: Boolean = false, // 添加验证状态字段
|
var isVerified: Boolean = false, // 添加验证状态字段
|
||||||
@@ -151,6 +152,7 @@ class ModuleViewModel : ViewModel() {
|
|||||||
obj.optString("updateJson"),
|
obj.optString("updateJson"),
|
||||||
obj.getBooleanCompat("web"),
|
obj.getBooleanCompat("web"),
|
||||||
obj.getBooleanCompat("action"),
|
obj.getBooleanCompat("action"),
|
||||||
|
obj.getBooleanCompat("metamodule"),
|
||||||
obj.optString("dir_id", obj.getString("id"))
|
obj.optString("dir_id", obj.getString("id"))
|
||||||
)
|
)
|
||||||
}.toList()
|
}.toList()
|
||||||
@@ -305,6 +307,7 @@ fun ModuleViewModel.ModuleInfo.copy(
|
|||||||
updateJson: String = this.updateJson,
|
updateJson: String = this.updateJson,
|
||||||
hasWebUi: Boolean = this.hasWebUi,
|
hasWebUi: Boolean = this.hasWebUi,
|
||||||
hasActionScript: Boolean = this.hasActionScript,
|
hasActionScript: Boolean = this.hasActionScript,
|
||||||
|
metamodule: Boolean = this.metamodule,
|
||||||
dirId: String = this.dirId,
|
dirId: String = this.dirId,
|
||||||
config: ModuleConfig? = this.config,
|
config: ModuleConfig? = this.config,
|
||||||
isVerified: Boolean = this.isVerified,
|
isVerified: Boolean = this.isVerified,
|
||||||
@@ -312,7 +315,7 @@ fun ModuleViewModel.ModuleInfo.copy(
|
|||||||
): ModuleViewModel.ModuleInfo {
|
): ModuleViewModel.ModuleInfo {
|
||||||
return ModuleViewModel.ModuleInfo(
|
return ModuleViewModel.ModuleInfo(
|
||||||
id, name, author, version, versionCode, description,
|
id, name, author, version, versionCode, description,
|
||||||
enabled, update, remove, updateJson, hasWebUi, hasActionScript,
|
enabled, update, remove, updateJson, hasWebUi, hasActionScript, metamodule,
|
||||||
dirId, config, isVerified, verificationTimestamp
|
dirId, config, isVerified, verificationTimestamp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -312,6 +312,16 @@ private fun HideOptionsSettings(
|
|||||||
onChange = handlers::handleHideZygiskImplementChange
|
onChange = handlers::handleHideZygiskImplementChange
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 元模块实现状态信息
|
||||||
|
SwitchSettingItem(
|
||||||
|
icon = Icons.Filled.VisibilityOff,
|
||||||
|
title = stringResource(R.string.hide_meta_module_implement),
|
||||||
|
summary = stringResource(R.string.hide_meta_module_implement_summary),
|
||||||
|
checked = state.isHideMetaModuleImplement,
|
||||||
|
onChange = handlers::handleHideMetaModuleImplementChange
|
||||||
|
)
|
||||||
|
|
||||||
|
// KPM 状态信息隐藏
|
||||||
if (Natives.version >= Natives.MINIMAL_SUPPORTED_KPM) {
|
if (Natives.version >= Natives.MINIMAL_SUPPORTED_KPM) {
|
||||||
SwitchSettingItem(
|
SwitchSettingItem(
|
||||||
icon = Icons.Filled.VisibilityOff,
|
icon = Icons.Filled.VisibilityOff,
|
||||||
|
|||||||
@@ -341,6 +341,14 @@ class MoreSettingsHandlers(
|
|||||||
state.isHideZygiskImplement = newValue
|
state.isHideZygiskImplement = newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理隐藏元模块实现变更
|
||||||
|
*/
|
||||||
|
fun handleHideMetaModuleImplementChange(newValue: Boolean) {
|
||||||
|
prefs.edit { putBoolean("is_hide_meta_module_Implement", newValue) }
|
||||||
|
state.isHideMetaModuleImplement = newValue
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理隐藏链接卡片变更
|
* 处理隐藏链接卡片变更
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class MoreSettingsState(
|
|||||||
var isHideOtherInfo by mutableStateOf(prefs.getBoolean("is_hide_other_info", false))
|
var isHideOtherInfo by mutableStateOf(prefs.getBoolean("is_hide_other_info", false))
|
||||||
var isShowKpmInfo by mutableStateOf(prefs.getBoolean("show_kpm_info", false))
|
var isShowKpmInfo by mutableStateOf(prefs.getBoolean("show_kpm_info", false))
|
||||||
var isHideZygiskImplement by mutableStateOf(prefs.getBoolean("is_hide_zygisk_Implement", false))
|
var isHideZygiskImplement by mutableStateOf(prefs.getBoolean("is_hide_zygisk_Implement", false))
|
||||||
|
var isHideMetaModuleImplement by mutableStateOf(prefs.getBoolean("is_hide_meta_module_Implement", false))
|
||||||
var isHideSusfsStatus by mutableStateOf(prefs.getBoolean("is_hide_susfs_status", false))
|
var isHideSusfsStatus by mutableStateOf(prefs.getBoolean("is_hide_susfs_status", false))
|
||||||
var isHideLinkCard by mutableStateOf(prefs.getBoolean("is_hide_link_card", false))
|
var isHideLinkCard by mutableStateOf(prefs.getBoolean("is_hide_link_card", false))
|
||||||
var isHideTagRow by mutableStateOf(prefs.getBoolean("is_hide_tag_row", false))
|
var isHideTagRow by mutableStateOf(prefs.getBoolean("is_hide_tag_row", false))
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
<string name="learn_more">了解更多</string>
|
||||||
<string name="home">主页</string>
|
<string name="home">主页</string>
|
||||||
<string name="home_not_installed">未安装</string>
|
<string name="home_not_installed">未安装</string>
|
||||||
<string name="home_click_to_install">点击安装</string>
|
<string name="home_click_to_install">点击安装</string>
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
<string name="reboot_edl">重启到 EDL</string>
|
<string name="reboot_edl">重启到 EDL</string>
|
||||||
<string name="about">关于</string>
|
<string name="about">关于</string>
|
||||||
<string name="module_uninstall_confirm">确定要卸载模块 %s 吗?</string>
|
<string name="module_uninstall_confirm">确定要卸载模块 %s 吗?</string>
|
||||||
|
<string name="metamodule_uninstall_confirm">"您确定要卸载模块 %s 吗?此操作将影响所有模块,并且元模块提供的某些功能(如挂载)将不再工作。 "</string>
|
||||||
<string name="module_uninstall_success">%s 已卸载</string>
|
<string name="module_uninstall_success">%s 已卸载</string>
|
||||||
<string name="module_uninstall_failed">卸载失败:%s</string>
|
<string name="module_uninstall_failed">卸载失败:%s</string>
|
||||||
<string name="module_version">版本</string>
|
<string name="module_version">版本</string>
|
||||||
@@ -188,10 +190,12 @@
|
|||||||
<string name="hide_susfs_status_summary">隐藏主页上的 SuSFS 状态信息</string>
|
<string name="hide_susfs_status_summary">隐藏主页上的 SuSFS 状态信息</string>
|
||||||
<string name="hide_zygisk_implement">隐藏 Zygisk 状态信息</string>
|
<string name="hide_zygisk_implement">隐藏 Zygisk 状态信息</string>
|
||||||
<string name="hide_zygisk_implement_summary">隐藏主页上的 Zygisk 实现状态信息</string>
|
<string name="hide_zygisk_implement_summary">隐藏主页上的 Zygisk 实现状态信息</string>
|
||||||
|
<string name="hide_meta_module_implement">隐藏元模块状态信息</string>
|
||||||
|
<string name="hide_meta_module_implement_summary">隐藏主页上的元模块实现状态信息</string>
|
||||||
<string name="hide_link_card">隐藏链接卡片</string>
|
<string name="hide_link_card">隐藏链接卡片</string>
|
||||||
<string name="hide_link_card_summary">隐藏主页上的链接卡片信息</string>
|
<string name="hide_link_card_summary">隐藏主页上的链接卡片信息</string>
|
||||||
<string name="hide_tag_card">隐藏模块标签行</string>
|
<string name="hide_tag_card">隐藏模块标签行</string>
|
||||||
<string name="hide_tag_card_summary">隐藏模块卡片中的文件夹名称和大小标签</string>
|
<string name="hide_tag_card_summary">隐藏模块卡片中的文件夹名称、大小标签和是否为元模块</string>
|
||||||
<string name="theme_mode">主题模式</string>
|
<string name="theme_mode">主题模式</string>
|
||||||
<string name="theme_follow_system">跟随系统</string>
|
<string name="theme_follow_system">跟随系统</string>
|
||||||
<string name="theme_light">浅色</string>
|
<string name="theme_light">浅色</string>
|
||||||
@@ -328,6 +332,8 @@
|
|||||||
<string name="module_failed_count">%d 个模块安装失败</string>
|
<string name="module_failed_count">%d 个模块安装失败</string>
|
||||||
<string name="module_download_error">模块下载失败</string>
|
<string name="module_download_error">模块下载失败</string>
|
||||||
<string name="kernel_flashing">内核刷写</string>
|
<string name="kernel_flashing">内核刷写</string>
|
||||||
|
<string name="warning_of_meta_module_title">需要元模块</string>
|
||||||
|
<string name="warning_of_meta_module_summary">这个模块需要挂载一些文件。需要安装元模块,使它正常工作</string>
|
||||||
<!-- 分类相关 -->
|
<!-- 分类相关 -->
|
||||||
<string name="category_all_apps">全部</string>
|
<string name="category_all_apps">全部</string>
|
||||||
<string name="category_root_apps">Root</string>
|
<string name="category_root_apps">Root</string>
|
||||||
@@ -588,6 +594,7 @@
|
|||||||
<string name="no_active_manager">无活跃管理器</string>
|
<string name="no_active_manager">无活跃管理器</string>
|
||||||
<string name="default_signature">SukiSU</string>
|
<string name="default_signature">SukiSU</string>
|
||||||
<string name="home_zygisk_implement">Zygisk 实现</string>
|
<string name="home_zygisk_implement">Zygisk 实现</string>
|
||||||
|
<string name="home_meta_module_implement">元模块实现</string>
|
||||||
<!-- 循环路径相关 -->
|
<!-- 循环路径相关 -->
|
||||||
<string name="susfs_tab_sus_loop_paths">SuS 循环路径</string>
|
<string name="susfs_tab_sus_loop_paths">SuS 循环路径</string>
|
||||||
<string name="susfs_add_sus_loop_path">添加 SuS 循环路径</string>
|
<string name="susfs_add_sus_loop_path">添加 SuS 循环路径</string>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name" translatable="false">SukiSU Ultra</string>
|
<string name="app_name" translatable="false">SukiSU Ultra</string>
|
||||||
<string name="home">Home</string>
|
<string name="home">Home</string>
|
||||||
|
<string name="learn_more">Learn more</string>
|
||||||
<string name="home_not_installed">Not installed</string>
|
<string name="home_not_installed">Not installed</string>
|
||||||
<string name="home_click_to_install">Click to install</string>
|
<string name="home_click_to_install">Click to install</string>
|
||||||
<string name="home_working">Working</string>
|
<string name="home_working">Working</string>
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
<string name="reboot_edl">Reboot to EDL</string>
|
<string name="reboot_edl">Reboot to EDL</string>
|
||||||
<string name="about">About</string>
|
<string name="about">About</string>
|
||||||
<string name="module_uninstall_confirm">Are you sure you want to uninstall module %s?</string>
|
<string name="module_uninstall_confirm">Are you sure you want to uninstall module %s?</string>
|
||||||
|
<string name="metamodule_uninstall_confirm">"Are you sure you want to uninstall module %s? This action will affect all modules, and certain features provided by the metamodule (such as mounting) will no longer work. "</string>
|
||||||
<string name="module_uninstall_success">%s uninstalled</string>
|
<string name="module_uninstall_success">%s uninstalled</string>
|
||||||
<string name="module_uninstall_failed">Failed to uninstall: %s</string>
|
<string name="module_uninstall_failed">Failed to uninstall: %s</string>
|
||||||
<string name="module_version">Version</string>
|
<string name="module_version">Version</string>
|
||||||
@@ -190,10 +192,12 @@
|
|||||||
<string name="hide_susfs_status_summary">Hide SuSFS status information on the home page</string>
|
<string name="hide_susfs_status_summary">Hide SuSFS status information on the home page</string>
|
||||||
<string name="hide_zygisk_implement">Hide Zygisk status</string>
|
<string name="hide_zygisk_implement">Hide Zygisk status</string>
|
||||||
<string name="hide_zygisk_implement_summary">Hide Zygisk implementation information on the home page</string>
|
<string name="hide_zygisk_implement_summary">Hide Zygisk implementation information on the home page</string>
|
||||||
|
<string name="hide_meta_module_implement">Hide Meta Module status</string>
|
||||||
|
<string name="hide_meta_module_implement_summary">Hide Meta Module implementation information on the home page</string>
|
||||||
<string name="hide_link_card">Hide Link Card Status</string>
|
<string name="hide_link_card">Hide Link Card Status</string>
|
||||||
<string name="hide_link_card_summary">Hide link card information on the home page</string>
|
<string name="hide_link_card_summary">Hide link card information on the home page</string>
|
||||||
<string name="hide_tag_card">Hide module label rows</string>
|
<string name="hide_tag_card">Hide module label rows</string>
|
||||||
<string name="hide_tag_card_summary">Hide folder name and size labels in module cards</string>
|
<string name="hide_tag_card_summary">Hide folder name,size,metamodule notice labels in module cards</string>
|
||||||
<string name="theme_mode">Theme</string>
|
<string name="theme_mode">Theme</string>
|
||||||
<string name="theme_follow_system">Follow system</string>
|
<string name="theme_follow_system">Follow system</string>
|
||||||
<string name="theme_light">Light</string>
|
<string name="theme_light">Light</string>
|
||||||
@@ -331,6 +335,8 @@
|
|||||||
<string name="module_failed_count">%d Failed to install a new module</string>
|
<string name="module_failed_count">%d Failed to install a new module</string>
|
||||||
<string name="module_download_error">Module download failed</string>
|
<string name="module_download_error">Module download failed</string>
|
||||||
<string name="kernel_flashing">Kernel Flashing</string>
|
<string name="kernel_flashing">Kernel Flashing</string>
|
||||||
|
<string name="warning_of_meta_module_title">Require Meta module</string>
|
||||||
|
<string name="warning_of_meta_module_summary">This module want to mount /system, meta module will handle that. Otherwise, it might not work.</string>
|
||||||
<!-- 分类相关 -->
|
<!-- 分类相关 -->
|
||||||
<string name="category_all_apps">All</string>
|
<string name="category_all_apps">All</string>
|
||||||
<string name="category_root_apps">Root</string>
|
<string name="category_root_apps">Root</string>
|
||||||
@@ -591,6 +597,7 @@
|
|||||||
<string name="no_active_manager">No active manager</string>
|
<string name="no_active_manager">No active manager</string>
|
||||||
<string name="default_signature">SukiSU</string>
|
<string name="default_signature">SukiSU</string>
|
||||||
<string name="home_zygisk_implement">Zygisk implement</string>
|
<string name="home_zygisk_implement">Zygisk implement</string>
|
||||||
|
<string name="home_meta_module_implement">Meta Module implement</string>
|
||||||
<!-- 循环路径相关 -->
|
<!-- 循环路径相关 -->
|
||||||
<string name="susfs_tab_sus_loop_paths">SUS Loop Paths</string>
|
<string name="susfs_tab_sus_loop_paths">SUS Loop Paths</string>
|
||||||
<string name="susfs_add_sus_loop_path">Add SUS Loop Path</string>
|
<string name="susfs_add_sus_loop_path">Add SUS Loop Path</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user