From c3533861f2ce735ea17caa7c82de20e91d6ce95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=A6=E7=92=83=E9=85=B1?= Date: Mon, 1 Sep 2025 15:04:58 +0800 Subject: [PATCH] manager: Optimized import, optimized all libsu shell calls, and fixed WebUI memory leaks (#369) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * manager: simply optimize * manager: optimize webui functions * manager: detect selinux using libsu:io * manager: optimize webui functions * manager: use the default shell * manager: optimize import * manager: optimize shell builder * manager: fix memory leaks * manager: optimize magisk detection * manager: use libsu * manager: optimize webui --------- Co-authored-by: 白彩恋 --- .../com/sukisu/ultra/KernelSUApplication.kt | 6 +- .../java/com/sukisu/ultra/ui/KsuService.kt | 8 +- .../java/com/sukisu/ultra/ui/MainActivity.kt | 32 +-- .../sukisu/ultra/ui/component/AboutCard.kt | 17 +- .../ultra/ui/component/FabVisibilityState.kt | 6 +- .../ultra/ui/component/ImageEditorDialog.kt | 11 +- .../sukisu/ultra/ui/component/SearchBar.kt | 26 +- .../sukisu/ultra/ui/component/SettingsItem.kt | 7 +- .../ultra/ui/component/SlotSelectionDialog.kt | 8 +- .../ultra/ui/component/SuSFSConfigDialogs.kt | 57 +---- .../ultra/ui/component/SuSFSConfigTabs.kt | 30 +-- .../ui/component/VerticalExpandableFab.kt | 6 +- .../ui/component/profile/AppProfileConfig.kt | 6 +- .../ui/component/profile/RootProfileConfig.kt | 29 +-- .../ui/component/profile/TemplateConfig.kt | 16 +- .../com/sukisu/ultra/ui/screen/AppProfile.kt | 56 +--- .../ultra/ui/screen/BottomBarDestination.kt | 9 +- .../ultra/ui/screen/ExecuteModuleAction.kt | 32 +-- .../java/com/sukisu/ultra/ui/screen/Flash.kt | 18 +- .../java/com/sukisu/ultra/ui/screen/Home.kt | 53 +--- .../com/sukisu/ultra/ui/screen/Install.kt | 59 +---- .../java/com/sukisu/ultra/ui/screen/Kpm.kt | 41 ++- .../java/com/sukisu/ultra/ui/screen/Module.kt | 58 ++--- .../com/sukisu/ultra/ui/screen/Settings.kt | 24 +- .../com/sukisu/ultra/ui/screen/SuSFSConfig.kt | 64 +---- .../com/sukisu/ultra/ui/screen/SuperUser.kt | 17 +- .../com/sukisu/ultra/ui/screen/Template.kt | 38 +-- .../sukisu/ultra/ui/screen/TemplateEditor.kt | 29 +-- .../com/sukisu/ultra/ui/theme/CardManage.kt | 6 +- .../java/com/sukisu/ultra/ui/theme/Theme.kt | 45 ++-- .../sukisu/ultra/ui/util/BackgroundUtils.kt | 2 +- .../com/sukisu/ultra/ui/util/Downloader.kt | 2 +- .../sukisu/ultra/ui/util/HanziToPinyin.java | 160 ++++++------ .../com/sukisu/ultra/ui/util/HyperlinkText.kt | 1 + .../java/com/sukisu/ultra/ui/util/KsuCli.kt | 241 ++++++------------ .../java/com/sukisu/ultra/ui/util/LogEvent.kt | 51 ++-- .../com/sukisu/ultra/ui/util/ModuleModify.kt | 9 +- .../com/sukisu/ultra/ui/util/ModuleUtils.kt | 11 +- .../ui/util/ModuleVerificationManager.kt | 17 +- .../sukisu/ultra/ui/util/SELinuxChecker.kt | 32 +-- .../com/sukisu/ultra/ui/util/SuSFSManager.kt | 17 +- .../ultra/ui/viewmodel/HomeViewModel.kt | 2 +- .../sukisu/ultra/ui/viewmodel/KpmViewModel.kt | 2 +- .../ultra/ui/viewmodel/ModuleViewModel.kt | 15 +- .../ultra/ui/viewmodel/SuperUserViewModel.kt | 37 +-- .../ultra/ui/viewmodel/TemplateViewModel.kt | 8 +- .../sukisu/ultra/ui/webui/KsuLibSuProvider.kt | 4 +- .../ultra/ui/webui/SuFilePathHandler.java | 2 - .../sukisu/ultra/ui/webui/WebUIActivity.kt | 26 +- .../sukisu/ultra/ui/webui/WebUIXActivity.kt | 6 +- .../sukisu/ultra/ui/webui/WebViewInterface.kt | 58 ++--- .../io/sukisu/ultra/UltraShellHelper.java | 13 +- .../io/sukisu/ultra/UltraToolInstall.java | 20 +- .../zakoui/activity/component/BottomBar.kt | 18 +- .../zakoui/activity/util/AnimatedBottomBar.kt | 6 +- .../zako/zako/zakoui/activity/util/AppData.kt | 13 +- .../zakoui/activity/util/DataRefreshUtils.kt | 2 +- .../zako/zakoui/activity/util/LocaleUtils.kt | 2 +- .../zako/zako/zakoui/flash/KernelFlash.kt | 44 +--- .../zako/zako/zakoui/screen/KernelFlash.kt | 17 +- .../zako/zako/zakoui/screen/MoreSettings.kt | 74 ++---- 61 files changed, 544 insertions(+), 1182 deletions(-) diff --git a/manager/app/src/main/java/com/sukisu/ultra/KernelSUApplication.kt b/manager/app/src/main/java/com/sukisu/ultra/KernelSUApplication.kt index 9660c6db..ea553ab0 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/KernelSUApplication.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/KernelSUApplication.kt @@ -12,10 +12,12 @@ import android.os.Bundle import coil.Coil import coil.ImageLoader import com.dergoogler.mmrl.platform.Platform +import com.sukisu.ultra.ui.util.createRootShellBuilder +import com.topjohnwu.superuser.Shell import me.zhanghai.android.appiconloader.coil.AppIconFetcher import me.zhanghai.android.appiconloader.coil.AppIconKeyer import java.io.File -import java.util.Locale +import java.util.* @SuppressLint("StaticFieldLeak") lateinit var ksuApp: KernelSUApplication @@ -86,6 +88,8 @@ class KernelSUApplication : Application() { override fun onCreate() { super.onCreate() ksuApp = this + Shell.setDefaultBuilder(createRootShellBuilder(true)) + Shell.enableVerboseLogging = BuildConfig.DEBUG // 注册Activity生命周期回调 registerActivityLifecycleCallbacks(activityLifecycleCallbacks) diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/KsuService.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/KsuService.kt index ed42b22b..41d0f433 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/KsuService.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/KsuService.kt @@ -2,11 +2,7 @@ package com.sukisu.ultra.ui import android.content.Intent import android.content.pm.PackageInfo -import android.os.Binder -import android.os.IBinder -import android.os.IInterface -import android.os.Parcel -import android.os.UserManager +import android.os.* import android.util.Log import com.topjohnwu.superuser.ipc.RootService import rikka.parcelablelist.ParcelableListSlice @@ -60,7 +56,7 @@ class KsuService : RootService() { val result = getPackages(flagsArg) reply?.writeNoException() reply?.writeInt(1) - result.writeToParcel(reply!!, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE) + result.writeToParcel(reply!!, Parcelable.PARCELABLE_WRITE_RETURN_VALUE) return true } } diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/MainActivity.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/MainActivity.kt index 6b8df7e0..ca0b9958 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/MainActivity.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/MainActivity.kt @@ -7,18 +7,15 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.compose.animation.AnimatedContentTransitionScope -import androidx.compose.animation.EnterTransition -import androidx.compose.animation.ExitTransition +import androidx.compose.animation.* import androidx.compose.animation.core.tween -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.scaleOut -import androidx.compose.animation.slideInHorizontally -import androidx.compose.animation.slideOutHorizontally -import androidx.compose.foundation.layout.* -import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHostState +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.lifecycle.lifecycleScope import androidx.navigation.NavBackStackEntry @@ -29,20 +26,19 @@ import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationSty import com.ramcosta.composedestinations.generated.NavGraphs import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination import com.ramcosta.composedestinations.spec.NavHostGraphSpec -import io.sukisu.ultra.UltraToolInstall -import com.sukisu.ultra.ksuApp -import zako.zako.zako.zakoui.activity.util.AppData +import com.sukisu.ultra.Natives import com.sukisu.ultra.ui.screen.BottomBarDestination -import com.sukisu.ultra.ui.theme.* -import zako.zako.zako.zakoui.activity.util.* -import zako.zako.zako.zakoui.activity.component.BottomBar +import com.sukisu.ultra.ui.theme.KernelSUTheme import com.sukisu.ultra.ui.util.LocalSnackbarHost import com.sukisu.ultra.ui.util.install import com.sukisu.ultra.ui.viewmodel.HomeViewModel import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel import com.sukisu.ultra.ui.webui.initPlatform +import io.sukisu.ultra.UltraToolInstall import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.launch +import zako.zako.zako.zakoui.activity.component.BottomBar +import zako.zako.zako.zakoui.activity.util.* class MainActivity : ComponentActivity() { private lateinit var superUserViewModel: SuperUserViewModel @@ -206,7 +202,7 @@ class MainActivity : ComponentActivity() { // 初始化主题相关设置 ThemeUtils.initializeThemeSettings(this, settingsStateFlow) - val isManager = AppData.isManager(ksuApp.packageName) + val isManager = Natives.becomeManager(packageName) if (isManager) { install() UltraToolInstall.tryToInstall() diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/AboutCard.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/AboutCard.kt index 6c2eb57a..5dcda95f 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/AboutCard.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/AboutCard.kt @@ -1,14 +1,7 @@ package com.sukisu.ultra.ui.component import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ElevatedCard @@ -21,11 +14,7 @@ import androidx.compose.ui.draw.scale import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.TextLinkStyles -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.fromHtml +import androidx.compose.ui.text.* import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -95,7 +84,7 @@ private fun AboutCardContent() { Spacer(modifier = Modifier.height(8.dp)) - val annotatedString = AnnotatedString.Companion.fromHtml( + val annotatedString = AnnotatedString.fromHtml( htmlString = stringResource( id = R.string.about_source_code, "GitHub", diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/FabVisibilityState.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/FabVisibilityState.kt index a87570ed..9042cdd9 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/FabVisibilityState.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/FabVisibilityState.kt @@ -1,12 +1,14 @@ package com.sukisu.ultra.ui.component import android.annotation.SuppressLint -import androidx.compose.animation.core.* import androidx.compose.animation.* -import androidx.compose.runtime.* +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.spring import androidx.compose.foundation.layout.Box import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.clip diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/ImageEditorDialog.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/ImageEditorDialog.kt index 46152d7f..4dd8b2e1 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/ImageEditorDialog.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/ImageEditorDialog.kt @@ -10,15 +10,20 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Check import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Fullscreen -import androidx.compose.material3.* +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp @@ -30,10 +35,6 @@ import com.sukisu.ultra.R import com.sukisu.ultra.ui.util.BackgroundTransformation import com.sukisu.ultra.ui.util.saveTransformedBackground import kotlinx.coroutines.launch -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.geometry.Size -import androidx.compose.ui.layout.onSizeChanged import kotlin.math.max @Composable diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SearchBar.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SearchBar.kt index 91d08b17..03deff54 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SearchBar.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SearchBar.kt @@ -4,35 +4,15 @@ import android.util.Log import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowBack import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarScrollBehavior -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SettingsItem.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SettingsItem.kt index 21a7cdfb..6ccf4285 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SettingsItem.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SettingsItem.kt @@ -3,12 +3,7 @@ package com.sukisu.ultra.ui.component import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.selection.toggleable -import androidx.compose.material3.Icon -import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Switch -import androidx.compose.material3.Text +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SlotSelectionDialog.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SlotSelectionDialog.kt index 8e083358..2f43c969 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SlotSelectionDialog.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SlotSelectionDialog.kt @@ -5,18 +5,18 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.SdStorage import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.sukisu.ultra.R -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.SdStorage -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.vector.ImageVector /** * 槽位选择对话框组件 diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigDialogs.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigDialogs.kt index c2e1df16..f3fb7804 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigDialogs.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigDialogs.kt @@ -5,62 +5,15 @@ import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.graphics.drawable.Drawable import android.util.Log -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.* +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.CheckCircle -import androidx.compose.material.icons.filled.Delete -import androidx.compose.material.icons.filled.Edit -import androidx.compose.material.icons.filled.Folder -import androidx.compose.material.icons.filled.PlayArrow -import androidx.compose.material.icons.filled.RadioButtonUnchecked -import androidx.compose.material.icons.filled.Search -import androidx.compose.material.icons.filled.Settings -import androidx.compose.material.icons.filled.Update -import androidx.compose.material.icons.filled.Visibility -import androidx.compose.material.icons.filled.VisibilityOff -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.MenuAnchorType -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Surface -import androidx.compose.material3.Switch -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigTabs.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigTabs.kt index 81fa74c0..5e2bd89c 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigTabs.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/SuSFSConfigTabs.kt @@ -1,37 +1,13 @@ package com.sukisu.ultra.ui.component import android.annotation.SuppressLint -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Add -import androidx.compose.material.icons.filled.Apps -import androidx.compose.material.icons.filled.Folder -import androidx.compose.material.icons.filled.Loop -import androidx.compose.material.icons.filled.PlayArrow -import androidx.compose.material.icons.filled.Security -import androidx.compose.material.icons.filled.Settings -import androidx.compose.material.icons.filled.Storage -import androidx.compose.material3.Button -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Switch -import androidx.compose.material3.Text +import androidx.compose.material.icons.filled.* +import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/VerticalExpandableFab.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/VerticalExpandableFab.kt index a1034765..914240ce 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/VerticalExpandableFab.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/VerticalExpandableFab.kt @@ -1,7 +1,9 @@ package com.sukisu.ultra.ui.component import androidx.compose.animation.* -import androidx.compose.animation.core.* +import androidx.compose.animation.core.FastOutSlowInEasing +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.tween import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* @@ -15,8 +17,8 @@ import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import com.sukisu.ultra.R // 菜单项数据类 diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/AppProfileConfig.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/AppProfileConfig.kt index ba0ce2a1..5ba96952 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/AppProfileConfig.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/AppProfileConfig.kt @@ -3,11 +3,7 @@ package com.sukisu.ultra.ui.component.profile import androidx.compose.foundation.layout.Column import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/RootProfileConfig.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/RootProfileConfig.kt index 704dbc3e..7593a491 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/RootProfileConfig.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/RootProfileConfig.kt @@ -1,28 +1,11 @@ package com.sukisu.ultra.ui.component.profile import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material3.AssistChip -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedCard -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.OutlinedTextFieldDefaults -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource @@ -34,11 +17,7 @@ import androidx.core.text.isDigitsOnly import com.maxkeppeker.sheets.core.models.base.Header import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState import com.maxkeppeler.sheets.input.InputDialog -import com.maxkeppeler.sheets.input.models.InputHeader -import com.maxkeppeler.sheets.input.models.InputSelection -import com.maxkeppeler.sheets.input.models.InputTextField -import com.maxkeppeler.sheets.input.models.InputTextFieldType -import com.maxkeppeler.sheets.input.models.ValidationResult +import com.maxkeppeler.sheets.input.models.* import com.maxkeppeler.sheets.list.ListDialog import com.maxkeppeler.sheets.list.models.ListOption import com.maxkeppeler.sheets.list.models.ListSelection diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/TemplateConfig.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/TemplateConfig.kt index 502b2932..08c093a3 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/TemplateConfig.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/component/profile/TemplateConfig.kt @@ -6,21 +6,9 @@ import androidx.compose.material.icons.automirrored.filled.ReadMore import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.ArrowDropUp import androidx.compose.material.icons.filled.Create -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.MenuAnchorType -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import com.sukisu.ultra.Natives diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/AppProfile.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/AppProfile.kt index 48cb22ef..bb8eca00 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/AppProfile.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/AppProfile.kt @@ -2,26 +2,9 @@ package com.sukisu.ultra.ui.screen import android.annotation.SuppressLint import androidx.annotation.StringRes -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.Crossfade -import androidx.compose.animation.expandVertically -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically +import androidx.compose.animation.* import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.BoxWithConstraints -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawing -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons @@ -29,31 +12,9 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.AccountCircle import androidx.compose.material.icons.filled.Android import androidx.compose.material.icons.filled.Security -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ElevatedCard -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.FilterChip -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarColors -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarScrollBehavior -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha @@ -86,12 +47,7 @@ import com.sukisu.ultra.ui.component.profile.TemplateConfig import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.theme.getCardColors import com.sukisu.ultra.ui.theme.getCardElevation -import com.sukisu.ultra.ui.util.LocalSnackbarHost -import com.sukisu.ultra.ui.util.forceStopApp -import com.sukisu.ultra.ui.util.getSepolicy -import com.sukisu.ultra.ui.util.launchApp -import com.sukisu.ultra.ui.util.restartApp -import com.sukisu.ultra.ui.util.setSepolicy +import com.sukisu.ultra.ui.util.* import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel import com.sukisu.ultra.ui.viewmodel.getTemplateInfoById import kotlinx.coroutines.launch @@ -386,7 +342,7 @@ private fun AppProfileInner( } } -private enum class Mode(@StringRes private val res: Int) { +private enum class Mode(@param:StringRes private val res: Int) { Default(R.string.profile_default), Template(R.string.profile_template), Custom(R.string.profile_custom); val text: String diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/BottomBarDestination.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/BottomBarDestination.kt index b2c72052..4175ecff 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/BottomBarDestination.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/BottomBarDestination.kt @@ -3,20 +3,15 @@ package com.sukisu.ultra.ui.screen import androidx.annotation.StringRes import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* -import androidx.compose.material.icons.filled.Archive import androidx.compose.material.icons.outlined.* import androidx.compose.ui.graphics.vector.ImageVector -import com.ramcosta.composedestinations.generated.destinations.HomeScreenDestination -import com.ramcosta.composedestinations.generated.destinations.ModuleScreenDestination -import com.ramcosta.composedestinations.generated.destinations.SuperUserScreenDestination -import com.ramcosta.composedestinations.generated.destinations.SettingScreenDestination -import com.ramcosta.composedestinations.generated.destinations.KpmScreenDestination +import com.ramcosta.composedestinations.generated.destinations.* import com.ramcosta.composedestinations.spec.DirectionDestinationSpec import com.sukisu.ultra.R enum class BottomBarDestination( val direction: DirectionDestinationSpec, - @StringRes val label: Int, + @param:StringRes val label: Int, val iconSelected: ImageVector, val iconNotSelected: ImageVector, val rootRequired: Boolean, diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/ExecuteModuleAction.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/ExecuteModuleAction.kt index 326c0010..26359a94 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/ExecuteModuleAction.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/ExecuteModuleAction.kt @@ -2,32 +2,15 @@ package com.sukisu.ultra.ui.screen import android.os.Environment import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.safeDrawing import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Save -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExtendedFloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SnackbarHost -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.input.key.Key import androidx.compose.ui.input.key.key @@ -37,17 +20,16 @@ import androidx.compose.ui.unit.dp import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import com.sukisu.ultra.R import com.sukisu.ultra.ui.component.KeyEventBlocker import com.sukisu.ultra.ui.util.LocalSnackbarHost import com.sukisu.ultra.ui.util.runModuleAction +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.io.File import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale +import java.util.* @Composable @Destination diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt index 55d83faf..d401806c 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt @@ -4,12 +4,8 @@ import android.net.Uri import android.os.Environment import android.os.Parcelable import androidx.activity.compose.BackHandler -import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.* import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.expandVertically -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState @@ -33,22 +29,22 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination import com.ramcosta.composedestinations.generated.destinations.ModuleScreenDestination import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator +import com.sukisu.ultra.R +import com.sukisu.ultra.ui.component.KeyEventBlocker +import com.sukisu.ultra.ui.theme.CardConfig +import com.sukisu.ultra.ui.util.* +import com.sukisu.ultra.ui.viewmodel.ModuleViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize -import com.sukisu.ultra.ui.component.KeyEventBlocker -import com.sukisu.ultra.ui.util.* -import com.sukisu.ultra.R -import com.sukisu.ultra.ui.theme.CardConfig -import com.sukisu.ultra.ui.viewmodel.ModuleViewModel -import androidx.lifecycle.viewmodel.compose.viewModel import java.io.File import java.text.SimpleDateFormat import java.util.* diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt index 0e61f504..2a657d94 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt @@ -6,29 +6,11 @@ import android.os.Build import android.os.PowerManager import android.system.Os import androidx.annotation.StringRes -import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.* import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring -import androidx.compose.animation.expandVertically -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawing -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll @@ -40,29 +22,8 @@ import androidx.compose.material.icons.outlined.TaskAlt import androidx.compose.material.icons.outlined.Warning import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ElevatedCard -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarScrollBehavior -import androidx.compose.material3.rememberTopAppBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -89,11 +50,11 @@ import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha import com.sukisu.ultra.ui.theme.CardConfig.cardElevation import com.sukisu.ultra.ui.theme.getCardColors import com.sukisu.ultra.ui.theme.getCardElevation +import com.sukisu.ultra.ui.util.SuSFSManager import com.sukisu.ultra.ui.util.checkNewVersion +import com.sukisu.ultra.ui.util.getSuSFS import com.sukisu.ultra.ui.util.module.LatestVersionInfo import com.sukisu.ultra.ui.util.reboot -import com.sukisu.ultra.ui.util.getSuSFS -import com.sukisu.ultra.ui.util.SuSFSManager import com.sukisu.ultra.ui.viewmodel.HomeViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -366,7 +327,7 @@ private fun StatusCard( systemStatus.ksuVersion != null -> { val workingModeText = when { - Natives.isSafeMode == true -> stringResource(id = R.string.safe_mode) + Natives.isSafeMode -> stringResource(id = R.string.safe_mode) else -> stringResource(id = R.string.home_working) } diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt index cc54ae3b..a0a910e1 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt @@ -7,22 +7,11 @@ import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.StringRes -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.expandVertically -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically +import androidx.compose.animation.* import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.verticalScroll @@ -30,31 +19,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.AutoFixHigh import androidx.compose.material.icons.filled.FileUpload -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.ElevatedCard -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.RadioButton -import androidx.compose.material3.RadioButtonDefaults -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarScrollBehavior -import androidx.compose.material3.rememberTopAppBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -78,22 +44,17 @@ import com.ramcosta.composedestinations.generated.destinations.KernelFlashScreen import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator import com.sukisu.ultra.R +import com.sukisu.ultra.getKernelVersion import com.sukisu.ultra.ui.component.DialogHandle import com.sukisu.ultra.ui.component.SlotSelectionDialog import com.sukisu.ultra.ui.component.rememberConfirmDialog import com.sukisu.ultra.ui.component.rememberCustomDialog +import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha import com.sukisu.ultra.ui.theme.CardConfig.cardElevation import com.sukisu.ultra.ui.theme.getCardColors -import com.sukisu.ultra.ui.util.LkmSelection -import com.sukisu.ultra.ui.util.getCurrentKmi -import com.sukisu.ultra.ui.util.getSupportedKmis -import com.sukisu.ultra.ui.util.isAbDevice -import com.sukisu.ultra.ui.util.isInitBoot -import com.sukisu.ultra.ui.util.rootAvailable -import com.sukisu.ultra.getKernelVersion -import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.theme.getCardElevation +import com.sukisu.ultra.ui.util.* /** * @author ShirkNeko @@ -413,9 +374,9 @@ private fun SelectInstallMethod( else -> null } - option?.let { it -> - selectedOption = it - onSelected(it) + option?.let { opt -> + selectedOption = opt + onSelected(opt) } } } diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Kpm.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Kpm.kt index 6f36c672..6f343176 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Kpm.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Kpm.kt @@ -1,5 +1,6 @@ package com.sukisu.ultra.ui.screen +import android.app.Activity import android.content.Context import android.content.Intent import android.util.Log @@ -17,25 +18,27 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.core.content.edit import androidx.lifecycle.viewmodel.compose.viewModel import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph +import com.sukisu.ultra.R +import com.sukisu.ultra.ui.component.* +import com.sukisu.ultra.ui.theme.getCardColors +import com.sukisu.ultra.ui.theme.getCardElevation +import com.sukisu.ultra.ui.util.loadKpmModule +import com.sukisu.ultra.ui.util.unloadKpmModule +import com.sukisu.ultra.ui.viewmodel.KpmViewModel +import com.topjohnwu.superuser.Shell import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import com.sukisu.ultra.ui.component.* -import com.sukisu.ultra.ui.theme.* -import com.sukisu.ultra.ui.viewmodel.KpmViewModel -import com.sukisu.ultra.ui.util.* import java.io.File -import androidx.core.content.edit -import com.sukisu.ultra.R import java.io.FileInputStream -import java.net.* -import android.app.Activity -import androidx.compose.ui.res.painterResource +import java.net.URLEncoder /** * KPM 管理界面 @@ -83,9 +86,8 @@ fun KpmScreen( LaunchedEffect(tempFileForInstall) { tempFileForInstall?.let { tempFile -> try { - val shell = getRootShell() val command = "strings ${tempFile.absolutePath} | grep 'name='" - val result = shell.newJob().add(command).to(ArrayList(), null).exec() + val result = Shell.cmd(command).to(ArrayList(), null).exec() if (result.isSuccess) { for (line in result.out) { if (line.startsWith("name=")) { @@ -424,9 +426,8 @@ private suspend fun handleModuleInstall( ) { var moduleId: String? = null try { - val shell = getRootShell() val command = "strings ${tempFile.absolutePath} | grep 'name='" - val result = shell.newJob().add(command).to(ArrayList(), null).exec() + val result = Shell.cmd(command).to(ArrayList(), null).exec() if (result.isSuccess) { for (line in result.out) { if (line.startsWith("name=")) { @@ -453,9 +454,8 @@ private suspend fun handleModuleInstall( try { if (isEmbed) { - val shell = getRootShell() - shell.newJob().add("mkdir -p /data/adb/kpm").exec() - shell.newJob().add("cp ${tempFile.absolutePath} $targetPath").exec() + Shell.cmd("mkdir -p /data/adb/kpm").exec() + Shell.cmd("cp ${tempFile.absolutePath} $targetPath").exec() } val loadResult = loadKpmModule(tempFile.absolutePath) @@ -499,8 +499,7 @@ private suspend fun handleModuleUninstall( val moduleFilePath = "/data/adb/kpm/$moduleFileName" val fileExists = try { - val shell = getRootShell() - val result = shell.newJob().add("ls /data/adb/kpm/$moduleFileName").exec() + val result = Shell.cmd("ls /data/adb/kpm/$moduleFileName").exec() result.isSuccess } catch (e: Exception) { Log.e("KsuCli", "Failed to check module file existence: ${e.message}", e) @@ -531,8 +530,7 @@ private suspend fun handleModuleUninstall( } if (fileExists) { - val shell = getRootShell() - shell.newJob().add("rm $moduleFilePath").exec() + Shell.cmd("rm $moduleFilePath").exec() } viewModel.fetchModuleList() @@ -703,9 +701,8 @@ private fun KpmModuleItem( } private fun checkStringsCommand(tempFile: File): Int { - val shell = getRootShell() val command = "strings ${tempFile.absolutePath} | grep -E 'name=|version=|license=|author='" - val result = shell.newJob().add(command).to(ArrayList(), null).exec() + val result = Shell.cmd(command).to(ArrayList(), null).exec() if (!result.isSuccess) { return 0 diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt index 8aa1f0a8..3f4ceadf 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt @@ -11,9 +11,12 @@ import android.util.Log import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.animation.* -import androidx.compose.animation.core.* -import androidx.compose.foundation.* +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.animation.core.spring +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.clickable +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState import androidx.compose.foundation.layout.* @@ -28,8 +31,9 @@ import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.outlined.* -import androidx.compose.material.icons.filled.* +import androidx.compose.material.icons.automirrored.outlined.Wysiwyg +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material.icons.filled.Verified import androidx.compose.material.icons.outlined.* import androidx.compose.material3.* import androidx.compose.material3.pulltorefresh.PullToRefreshBox @@ -41,7 +45,8 @@ import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.platform.* +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role @@ -52,45 +57,32 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.core.content.edit +import androidx.core.net.toUri import androidx.lifecycle.viewmodel.compose.viewModel +import com.dergoogler.mmrl.platform.Platform +import com.dergoogler.mmrl.platform.model.ModuleConfig +import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator +import com.sukisu.ultra.Natives +import com.sukisu.ultra.R +import com.sukisu.ultra.ui.component.* +import com.sukisu.ultra.ui.theme.getCardColors +import com.sukisu.ultra.ui.theme.getCardElevation +import com.sukisu.ultra.ui.util.* +import com.sukisu.ultra.ui.viewmodel.ModuleViewModel +import com.sukisu.ultra.ui.webui.WebUIActivity +import com.sukisu.ultra.ui.webui.WebUIXActivity import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import com.sukisu.ultra.Natives -import com.sukisu.ultra.ui.component.ConfirmResult -import com.sukisu.ultra.ui.component.SearchAppBar -import com.sukisu.ultra.ui.component.rememberConfirmDialog -import com.sukisu.ultra.ui.component.rememberLoadingDialog -import com.sukisu.ultra.ui.util.DownloadListener -import com.sukisu.ultra.ui.util.* -import com.sukisu.ultra.ui.util.download -import com.sukisu.ultra.ui.util.hasMagisk -import com.sukisu.ultra.ui.util.reboot -import com.sukisu.ultra.ui.util.restoreModule -import com.sukisu.ultra.ui.util.toggleModule -import com.sukisu.ultra.ui.util.uninstallModule -import com.sukisu.ultra.ui.webui.WebUIActivity import okhttp3.OkHttpClient -import com.sukisu.ultra.ui.util.ModuleModify -import com.sukisu.ultra.ui.theme.getCardColors -import com.sukisu.ultra.ui.viewmodel.ModuleViewModel import java.util.concurrent.TimeUnit -import androidx.core.content.edit -import com.sukisu.ultra.R -import com.sukisu.ultra.ui.webui.WebUIXActivity -import com.dergoogler.mmrl.platform.Platform -import androidx.core.net.toUri -import com.dergoogler.mmrl.platform.model.ModuleConfig -import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig -import com.sukisu.ultra.ui.component.AnimatedFab -import com.sukisu.ultra.ui.component.rememberFabVisibilityState -import com.sukisu.ultra.ui.theme.getCardElevation // 菜单项数据类 data class ModuleBottomSheetMenuItem( diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt index d0484fef..7f6314ef 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt @@ -6,11 +6,7 @@ import android.net.Uri import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.expandVertically -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically +import androidx.compose.animation.* import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -21,13 +17,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Undo import androidx.compose.material.icons.filled.* import androidx.compose.material3.* -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -47,20 +38,21 @@ import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplat import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination import com.ramcosta.composedestinations.generated.destinations.MoreSettingsScreenDestination import com.ramcosta.composedestinations.navigation.DestinationsNavigator -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import com.sukisu.ultra.BuildConfig import com.sukisu.ultra.Natives import com.sukisu.ultra.R import com.sukisu.ultra.ui.component.* -import com.sukisu.ultra.ui.theme.* +import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha +import com.sukisu.ultra.ui.theme.getCardColors +import com.sukisu.ultra.ui.theme.getCardElevation import com.sukisu.ultra.ui.util.LocalSnackbarHost import com.sukisu.ultra.ui.util.getBugreportFile +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import java.time.LocalDateTime import java.time.format.DateTimeFormatter -import com.sukisu.ultra.ui.component.KsuIsValid /** * @author ShirkNeko diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt index 68419044..583207b2 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt @@ -3,58 +3,15 @@ package com.sukisu.ultra.ui.screen import android.annotation.SuppressLint import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawing -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.* -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.CenterAlignedTopAppBar -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.MenuAnchorType -import androidx.compose.material3.OutlinedButton -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Scaffold -import androidx.compose.material3.ScrollableTabRow -import androidx.compose.material3.Surface -import androidx.compose.material3.Switch -import androidx.compose.material3.Tab -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -68,18 +25,7 @@ import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.sukisu.ultra.R -import com.sukisu.ultra.ui.component.AddAppPathDialog -import com.sukisu.ultra.ui.component.AddKstatStaticallyDialog -import com.sukisu.ultra.ui.component.AddPathDialog -import com.sukisu.ultra.ui.component.AddTryUmountDialog -import com.sukisu.ultra.ui.component.ConfirmDialog -import com.sukisu.ultra.ui.component.EnabledFeaturesContent -import com.sukisu.ultra.ui.component.KstatConfigContent -import com.sukisu.ultra.ui.component.PathSettingsContent -import com.sukisu.ultra.ui.component.SusMountsContent -import com.sukisu.ultra.ui.component.SusPathsContent -import com.sukisu.ultra.ui.component.SusLoopPathsContent -import com.sukisu.ultra.ui.component.TryUmountContent +import com.sukisu.ultra.ui.component.* import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.util.SuSFSManager import com.sukisu.ultra.ui.util.SuSFSManager.isSusVersion158 @@ -1171,7 +1117,7 @@ fun SuSFSConfigScreen( containerColor = MaterialTheme.colorScheme.surface, contentColor = MaterialTheme.colorScheme.onSurface ) { - allTabs.forEachIndexed { index, tab -> + allTabs.forEach { tab -> Tab( selected = selectedTab == tab, onClick = { selectedTab = tab }, diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt index fad39069..e2434b74 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import androidx.compose.animation.* import androidx.compose.animation.core.* import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.collectIsPressedAsState @@ -17,7 +18,6 @@ import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.clickable import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.* @@ -34,31 +34,30 @@ import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.viewmodel.compose.viewModel -import com.sukisu.ultra.R import coil.compose.AsyncImage import coil.request.ImageRequest +import com.dergoogler.mmrl.ui.component.LabelItem +import com.dergoogler.mmrl.ui.component.LabelItemDefaults import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.generated.destinations.AppProfileScreenDestination import com.ramcosta.composedestinations.navigation.DestinationsNavigator -import kotlinx.coroutines.launch import com.sukisu.ultra.Natives +import com.sukisu.ultra.R +import com.sukisu.ultra.ui.component.FabMenuPresets import com.sukisu.ultra.ui.component.SearchAppBar import com.sukisu.ultra.ui.component.VerticalExpandableFab -import com.sukisu.ultra.ui.component.FabMenuPresets import com.sukisu.ultra.ui.util.ModuleModify -import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel import com.sukisu.ultra.ui.viewmodel.AppCategory import com.sukisu.ultra.ui.viewmodel.SortType -import com.dergoogler.mmrl.ui.component.LabelItem -import com.dergoogler.mmrl.ui.component.LabelItemDefaults -import kotlin.math.* +import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel +import kotlinx.coroutines.launch import java.io.File // 应用优先级枚举 diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Template.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Template.kt index ac07fc6c..41eb32ff 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Template.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Template.kt @@ -4,16 +4,7 @@ import android.content.ClipData import android.content.ClipboardManager import android.widget.Toast import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ExperimentalLayoutApi -import androidx.compose.foundation.layout.FlowRow -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.ExperimentalMaterialApi @@ -22,28 +13,9 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.ImportExport import androidx.compose.material.icons.filled.Sync -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExtendedFloatingActionButton -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarScrollBehavior +import androidx.compose.material3.* import androidx.compose.material3.pulltorefresh.PullToRefreshBox -import androidx.compose.material3.rememberTopAppBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext @@ -58,11 +30,11 @@ import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScr import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.result.ResultRecipient import com.ramcosta.composedestinations.result.getOr -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import com.sukisu.ultra.R import com.sukisu.ultra.ui.theme.CardConfig import com.sukisu.ultra.ui.viewmodel.TemplateViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch /** * @author weishu diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/TemplateEditor.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/TemplateEditor.kt index d00ad186..89e3e7b4 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/TemplateEditor.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/TemplateEditor.kt @@ -2,13 +2,7 @@ package com.sukisu.ultra.ui.screen import android.widget.Toast import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions @@ -17,24 +11,9 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.DeleteForever import androidx.compose.material.icons.filled.Save -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.ListItem -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.TopAppBarScrollBehavior -import androidx.compose.material3.rememberTopAppBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.material3.* +import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.input.nestedscroll.nestedScroll @@ -44,6 +23,7 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType +import androidx.lifecycle.compose.dropUnlessResumed import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.result.ResultBackNavigator @@ -55,7 +35,6 @@ import com.sukisu.ultra.ui.util.getAppProfileTemplate import com.sukisu.ultra.ui.util.setAppProfileTemplate import com.sukisu.ultra.ui.viewmodel.TemplateViewModel import com.sukisu.ultra.ui.viewmodel.toJSON -import androidx.lifecycle.compose.dropUnlessResumed /** * @author weishu diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/theme/CardManage.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/theme/CardManage.kt index 806ccc4f..e05ce3ba 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/theme/CardManage.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/theme/CardManage.kt @@ -3,11 +3,7 @@ package com.sukisu.ultra.ui.theme import android.content.Context import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.CardDefaults -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.luminance import androidx.compose.ui.unit.dp diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/theme/Theme.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/theme/Theme.kt index f7e02669..ad8cb631 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/theme/Theme.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/theme/Theme.kt @@ -5,51 +5,40 @@ import android.content.Context import android.net.Uri import android.os.Build import android.util.Log +import androidx.activity.ComponentActivity +import androidx.activity.SystemBarStyle +import androidx.activity.enableEdgeToEdge import androidx.annotation.RequiresApi import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.spring import androidx.compose.animation.core.updateTransition +import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.paint import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex +import androidx.core.content.edit +import androidx.core.net.toUri import coil.compose.AsyncImagePainter import coil.compose.rememberAsyncImagePainter -import androidx.compose.foundation.background -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.unit.dp +import com.sukisu.ultra.ui.util.BackgroundTransformation +import com.sukisu.ultra.ui.util.saveTransformedBackground import java.io.File import java.io.FileOutputStream import java.io.InputStream -import androidx.core.content.edit -import androidx.core.net.toUri -import com.sukisu.ultra.ui.util.BackgroundTransformation -import com.sukisu.ultra.ui.util.saveTransformedBackground -import androidx.activity.SystemBarStyle -import androidx.activity.ComponentActivity -import androidx.activity.enableEdgeToEdge -import androidx.compose.material3.ColorScheme -import androidx.compose.runtime.SideEffect -import androidx.compose.ui.graphics.toArgb /** * 主题配置对象,管理应用的主题相关状态 @@ -166,8 +155,8 @@ fun KernelSUTheme( val bgImagePainter = backgroundUri.value?.let { rememberAsyncImagePainter( model = it, - onError = { - Log.e("ThemeSystem", "背景图加载失败: ${it.result.throwable.message}") + onError = { err -> + Log.e("ThemeSystem", "背景图加载失败: ${err.result.throwable.message}") ThemeConfig.customBackgroundUri = null context.saveCustomBackground(null) }, @@ -222,7 +211,7 @@ fun KernelSUTheme( ) // 自定义背景层 - backgroundUri.value?.let { uri -> + backgroundUri.value?.let { Box( modifier = Modifier .fillMaxSize() diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/BackgroundUtils.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/BackgroundUtils.kt index 498d49d4..1f662214 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/BackgroundUtils.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/BackgroundUtils.kt @@ -8,10 +8,10 @@ import android.graphics.Canvas import android.graphics.Matrix import android.net.Uri import android.util.Log +import androidx.core.graphics.createBitmap import java.io.File import java.io.FileOutputStream import java.io.InputStream -import androidx.core.graphics.createBitmap data class BackgroundTransformation( val scale: Float = 1f, diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/Downloader.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/Downloader.kt index af7a314a..035137fd 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/Downloader.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/Downloader.kt @@ -15,8 +15,8 @@ import android.util.Log import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.core.content.ContextCompat -import com.sukisu.ultra.ui.util.module.LatestVersionInfo import androidx.core.net.toUri +import com.sukisu.ultra.ui.util.module.LatestVersionInfo import java.io.File import java.util.concurrent.TimeUnit diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/HanziToPinyin.java b/manager/app/src/main/java/com/sukisu/ultra/ui/util/HanziToPinyin.java index b7104115..fe1ebe69 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/HanziToPinyin.java +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/HanziToPinyin.java @@ -32,7 +32,8 @@ import java.util.Locale; *

* Currently this file is aligned to zh.txt in ICU 4.6 */ -public class HanziToPinyin { +@SuppressWarnings("SizeReplaceableByIsEmpty") +public record HanziToPinyin(boolean mHasChinaCollator) { private static final String TAG = "HanziToPinyin"; // Turn on this flag when we want to check internal data structure. @@ -44,77 +45,77 @@ public class HanziToPinyin { * Each unihans is the first one within same pinyin when collator is zh_CN. */ public static final char[] UNIHANS = { - '\u963f', '\u54ce', '\u5b89', '\u80ae', '\u51f9', '\u516b', - '\u6300', '\u6273', '\u90a6', '\u52f9', '\u9642', '\u5954', - '\u4f3b', '\u5c44', '\u8fb9', '\u706c', '\u618b', '\u6c43', - '\u51ab', '\u7676', '\u5cec', '\u5693', '\u5072', '\u53c2', - '\u4ed3', '\u64a1', '\u518a', '\u5d7e', '\u66fd', '\u66fe', - '\u5c64', '\u53c9', '\u8286', '\u8fbf', '\u4f25', '\u6284', - '\u8f66', '\u62bb', '\u6c88', '\u6c89', '\u9637', '\u5403', - '\u5145', '\u62bd', '\u51fa', '\u6b3b', '\u63e3', '\u5ddb', - '\u5205', '\u5439', '\u65fe', '\u9034', '\u5472', '\u5306', - '\u51d1', '\u7c97', '\u6c46', '\u5d14', '\u90a8', '\u6413', - '\u5491', '\u5446', '\u4e39', '\u5f53', '\u5200', '\u561a', - '\u6265', '\u706f', '\u6c10', '\u55f2', '\u7538', '\u5201', - '\u7239', '\u4e01', '\u4e1f', '\u4e1c', '\u543a', '\u53be', - '\u8011', '\u8968', '\u5428', '\u591a', '\u59b8', '\u8bf6', - '\u5940', '\u97a5', '\u513f', '\u53d1', '\u5e06', '\u531a', - '\u98de', '\u5206', '\u4e30', '\u8985', '\u4ecf', '\u7d11', - '\u4f15', '\u65ee', '\u4f85', '\u7518', '\u5188', '\u768b', - '\u6208', '\u7ed9', '\u6839', '\u522f', '\u5de5', '\u52fe', - '\u4f30', '\u74dc', '\u4e56', '\u5173', '\u5149', '\u5f52', - '\u4e28', '\u5459', '\u54c8', '\u548d', '\u4f44', '\u592f', - '\u8320', '\u8bc3', '\u9ed2', '\u62eb', '\u4ea8', '\u5677', - '\u53ff', '\u9f41', '\u4e6f', '\u82b1', '\u6000', '\u72bf', - '\u5ddf', '\u7070', '\u660f', '\u5419', '\u4e0c', '\u52a0', - '\u620b', '\u6c5f', '\u827d', '\u9636', '\u5dfe', '\u5755', - '\u5182', '\u4e29', '\u51e5', '\u59e2', '\u5658', '\u519b', - '\u5494', '\u5f00', '\u520a', '\u5ffc', '\u5c3b', '\u533c', - '\u808e', '\u52a5', '\u7a7a', '\u62a0', '\u625d', '\u5938', - '\u84af', '\u5bbd', '\u5321', '\u4e8f', '\u5764', '\u6269', - '\u5783', '\u6765', '\u5170', '\u5577', '\u635e', '\u808b', - '\u52d2', '\u5d1a', '\u5215', '\u4fe9', '\u5941', '\u826f', - '\u64a9', '\u5217', '\u62ce', '\u5222', '\u6e9c', '\u56d6', - '\u9f99', '\u779c', '\u565c', '\u5a08', '\u7567', '\u62a1', - '\u7f57', '\u5463', '\u5988', '\u57cb', '\u5ada', '\u7264', - '\u732b', '\u4e48', '\u5445', '\u95e8', '\u753f', '\u54aa', - '\u5b80', '\u55b5', '\u4e5c', '\u6c11', '\u540d', '\u8c2c', - '\u6478', '\u54de', '\u6bea', '\u55ef', '\u62cf', '\u8149', - '\u56e1', '\u56d4', '\u5b6c', '\u7592', '\u5a1e', '\u6041', - '\u80fd', '\u59ae', '\u62c8', '\u5b22', '\u9e1f', '\u634f', - '\u56dc', '\u5b81', '\u599e', '\u519c', '\u7fba', '\u5974', - '\u597b', '\u759f', '\u9ec1', '\u90cd', '\u5594', '\u8bb4', - '\u5991', '\u62cd', '\u7705', '\u4e53', '\u629b', '\u5478', - '\u55b7', '\u5309', '\u4e15', '\u56e8', '\u527d', '\u6c15', - '\u59d8', '\u4e52', '\u948b', '\u5256', '\u4ec6', '\u4e03', - '\u6390', '\u5343', '\u545b', '\u6084', '\u767f', '\u4eb2', - '\u72c5', '\u828e', '\u4e18', '\u533a', '\u5cd1', '\u7f3a', - '\u590b', '\u5465', '\u7a63', '\u5a06', '\u60f9', '\u4eba', - '\u6254', '\u65e5', '\u8338', '\u53b9', '\u909a', '\u633c', - '\u5827', '\u5a51', '\u77a4', '\u637c', '\u4ee8', '\u6be2', - '\u4e09', '\u6852', '\u63bb', '\u95aa', '\u68ee', '\u50e7', - '\u6740', '\u7b5b', '\u5c71', '\u4f24', '\u5f30', '\u5962', - '\u7533', '\u8398', '\u6552', '\u5347', '\u5c38', '\u53ce', - '\u4e66', '\u5237', '\u8870', '\u95e9', '\u53cc', '\u8c01', - '\u542e', '\u8bf4', '\u53b6', '\u5fea', '\u635c', '\u82cf', - '\u72fb', '\u590a', '\u5b59', '\u5506', '\u4ed6', '\u56fc', - '\u574d', '\u6c64', '\u5932', '\u5fd1', '\u71a5', '\u5254', - '\u5929', '\u65eb', '\u5e16', '\u5385', '\u56f2', '\u5077', - '\u51f8', '\u6e4d', '\u63a8', '\u541e', '\u4e47', '\u7a75', - '\u6b6a', '\u5f2f', '\u5c23', '\u5371', '\u6637', '\u7fc1', - '\u631d', '\u4e4c', '\u5915', '\u8672', '\u4eda', '\u4e61', - '\u7071', '\u4e9b', '\u5fc3', '\u661f', '\u51f6', '\u4f11', - '\u5401', '\u5405', '\u524a', '\u5743', '\u4e2b', '\u6079', - '\u592e', '\u5e7a', '\u503b', '\u4e00', '\u56d9', '\u5e94', - '\u54df', '\u4f63', '\u4f18', '\u625c', '\u56e6', '\u66f0', - '\u6655', '\u7b60', '\u7b7c', '\u5e00', '\u707d', '\u5142', - '\u5328', '\u50ae', '\u5219', '\u8d3c', '\u600e', '\u5897', - '\u624e', '\u635a', '\u6cbe', '\u5f20', '\u957f', '\u9577', - '\u4f4b', '\u8707', '\u8d1e', '\u4e89', '\u4e4b', '\u5cd9', - '\u5ea2', '\u4e2d', '\u5dde', '\u6731', '\u6293', '\u62fd', - '\u4e13', '\u5986', '\u96b9', '\u5b92', '\u5353', '\u4e72', - '\u5b97', '\u90b9', '\u79df', '\u94bb', '\u539c', '\u5c0a', - '\u6628', '\u5159', '\u9fc3', '\u9fc4',}; + '阿', '哎', '安', '肮', '凹', '八', + '挀', '扳', '邦', '勹', '陂', '奔', + '伻', '屄', '边', '灬', '憋', '汃', + '冫', '癶', '峬', '嚓', '偲', '参', + '仓', '撡', '冊', '嵾', '曽', '曾', + '層', '叉', '芆', '辿', '伥', '抄', + '车', '抻', '沈', '沉', '阷', '吃', + '充', '抽', '出', '欻', '揣', '巛', + '刅', '吹', '旾', '逴', '呲', '匆', + '凑', '粗', '汆', '崔', '邨', '搓', + '咑', '呆', '丹', '当', '刀', '嘚', + '扥', '灯', '氐', '嗲', '甸', '刁', + '爹', '丁', '丟', '东', '吺', '厾', + '耑', '襨', '吨', '多', '妸', '诶', + '奀', '鞥', '儿', '发', '帆', '匚', + '飞', '分', '丰', '覅', '仏', '紑', + '伕', '旮', '侅', '甘', '冈', '皋', + '戈', '给', '根', '刯', '工', '勾', + '估', '瓜', '乖', '关', '光', '归', + '丨', '呙', '哈', '咍', '佄', '夯', + '茠', '诃', '黒', '拫', '亨', '噷', + '叿', '齁', '乯', '花', '怀', '犿', + '巟', '灰', '昏', '吙', '丌', '加', + '戋', '江', '艽', '阶', '巾', '坕', + '冂', '丩', '凥', '姢', '噘', '军', + '咔', '开', '刊', '忼', '尻', '匼', + '肎', '劥', '空', '抠', '扝', '夸', + '蒯', '宽', '匡', '亏', '坤', '扩', + '垃', '来', '兰', '啷', '捞', '肋', + '勒', '崚', '刕', '俩', '奁', '良', + '撩', '列', '拎', '刢', '溜', '囖', + '龙', '瞜', '噜', '娈', '畧', '抡', + '罗', '呣', '妈', '埋', '嫚', '牤', + '猫', '么', '呅', '门', '甿', '咪', + '宀', '喵', '乜', '民', '名', '谬', + '摸', '哞', '毪', '嗯', '拏', '腉', + '囡', '囔', '孬', '疒', '娞', '恁', + '能', '妮', '拈', '嬢', '鸟', '捏', + '囜', '宁', '妞', '农', '羺', '奴', + '奻', '疟', '黁', '郍', '喔', '讴', + '妑', '拍', '眅', '乓', '抛', '呸', + '喷', '匉', '丕', '囨', '剽', '氕', + '姘', '乒', '钋', '剖', '仆', '七', + '掐', '千', '呛', '悄', '癿', '亲', + '狅', '芎', '丘', '区', '峑', '缺', + '夋', '呥', '穣', '娆', '惹', '人', + '扔', '日', '茸', '厹', '邚', '挼', + '堧', '婑', '瞤', '捼', '仨', '毢', + '三', '桒', '掻', '閪', '森', '僧', + '杀', '筛', '山', '伤', '弰', '奢', + '申', '莘', '敒', '升', '尸', '収', + '书', '刷', '衰', '闩', '双', '谁', + '吮', '说', '厶', '忪', '捜', '苏', + '狻', '夊', '孙', '唆', '他', '囼', + '坍', '汤', '夲', '忑', '熥', '剔', + '天', '旫', '帖', '厅', '囲', '偷', + '凸', '湍', '推', '吞', '乇', '穵', + '歪', '弯', '尣', '危', '昷', '翁', + '挝', '乌', '夕', '虲', '仚', '乡', + '灱', '些', '心', '星', '凶', '休', + '吁', '吅', '削', '坃', '丫', '恹', + '央', '幺', '倻', '一', '囙', '应', + '哟', '佣', '优', '扜', '囦', '曰', + '晕', '筠', '筼', '帀', '災', '兂', + '匨', '傮', '则', '贼', '怎', '増', + '扎', '捚', '沾', '张', '长', '長', + '佋', '蜇', '贞', '争', '之', '峙', + '庢', '中', '州', '朱', '抓', '拽', + '专', '妆', '隹', '宒', '卓', '乲', + '宗', '邹', '租', '钻', '厜', '尊', + '昨', '兙', '鿃', '鿄'}; /** * Pinyin array. @@ -334,18 +335,17 @@ public class HanziToPinyin { {90, 85, 0, 0, 0, 0}, {90, 85, 65, 78, 0, 0}, {90, 85, 73, 0, 0, 0}, {90, 85, 78, 0, 0, 0}, {90, 85, 79, 0, 0, 0}, {0, 0, 0, 0, 0, 0}, - {83, 72, 65, 78, 0, 0}, {0, 0, 0, 0, 0, 0},}; + {83, 72, 65, 78, 0, 0}, {0, 0, 0, 0, 0, 0}}; /** * First and last Chinese character with known Pinyin according to zh collation */ - private static final String FIRST_PINYIN_UNIHAN = "\u963F"; - private static final String LAST_PINYIN_UNIHAN = "\u9FFF"; + private static final String FIRST_PINYIN_UNIHAN = "阿"; + private static final String LAST_PINYIN_UNIHAN = "鿿"; private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA); private static HanziToPinyin sInstance; - private final boolean mHasChinaCollator; public static class Token { /** @@ -381,10 +381,6 @@ public class HanziToPinyin { public String target; } - protected HanziToPinyin(boolean hasChinaCollator) { - mHasChinaCollator = hasChinaCollator; - } - public static HanziToPinyin getInstance() { synchronized (HanziToPinyin.class) { if (sInstance != null) { @@ -402,8 +398,8 @@ public class HanziToPinyin { return sInstance; } } - if (sInstance == null){//这个判断是用于处理国产ROM的兼容性问题 - if (Locale.CHINA.equals(Locale.getDefault())){ + if (sInstance == null) {//这个判断是用于处理国产ROM的兼容性问题 + if (Locale.CHINA.equals(Locale.getDefault())) { sInstance = new HanziToPinyin(true); return sInstance; } diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/HyperlinkText.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/HyperlinkText.kt index bdd9b6fb..36ea19c3 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/HyperlinkText.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/HyperlinkText.kt @@ -76,6 +76,7 @@ private data class LinkInfo( val end: Int ) +@Suppress("HttpUrlsUsage") private fun extractUrls(text: String): List = buildList { val matcher = urlPattern.matcher(text) while (matcher.find()) { diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt index 16c90b68..f12c06dd 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt @@ -10,15 +10,15 @@ import android.os.SystemClock import android.provider.OpenableColumns import android.system.Os import android.util.Log +import com.sukisu.ultra.Natives +import com.sukisu.ultra.ksuApp import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.ShellUtils +import com.topjohnwu.superuser.io.SuFile import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import kotlinx.parcelize.Parcelize -import com.sukisu.ultra.BuildConfig -import com.sukisu.ultra.Natives -import com.sukisu.ultra.ksuApp import org.json.JSONArray import java.io.File @@ -29,19 +29,8 @@ import java.io.File */ private const val TAG = "KsuCli" -private fun getKsuDaemonPath(): String { - return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libzakozako.so" -} - -object KsuCli { - val SHELL: Shell = createRootShell() - val GLOBAL_MNT_SHELL: Shell = createRootShell(true) -} - -fun getRootShell(globalMnt: Boolean = false): Shell { - return if (globalMnt) KsuCli.GLOBAL_MNT_SHELL else { - KsuCli.SHELL - } +private val ksuDaemonPath by lazy { + "${ksuApp.applicationInfo.nativeLibraryDir}${File.separator}libzakozako.so" } inline fun withNewRootShell( @@ -63,37 +52,39 @@ fun Uri.getFileName(context: Context): String? { return fileName } +fun createRootShellBuilder(globalMnt: Boolean = false): Shell.Builder { + return Shell.Builder.create().run { + val cmd = buildString { + append("$ksuDaemonPath debug su") + if (globalMnt) append(" -g") + append(" || ") + append("su") + if (globalMnt) append(" --mount-master") + append(" || ") + append("sh") + } + setCommands("sh", "-c", cmd) + } +} + fun createRootShell(globalMnt: Boolean = false): Shell { - Shell.enableVerboseLogging = BuildConfig.DEBUG - val builder = Shell.Builder.create() - return try { - if (globalMnt) { - builder.build(getKsuDaemonPath(), "debug", "su", "-g") - } else { - builder.build(getKsuDaemonPath(), "debug", "su") - } - } catch (e: Throwable) { - Log.w(TAG, "ksu failed: ", e) - try { - if (globalMnt) { - builder.build("su", "-mm") - } else { - builder.build("su") - } - } catch (e: Throwable) { - Log.e(TAG, "su failed: ", e) - builder.build("sh") - } + return runCatching { + createRootShellBuilder(globalMnt).build() + }.getOrElse { e -> + Log.w(TAG, "su failed: ", e) + Shell.Builder.create().apply { + if (globalMnt) setFlags(Shell.FLAG_MOUNT_MASTER) + }.build() } } fun execKsud(args: String, newShell: Boolean = false): Boolean { return if (newShell) { withNewRootShell { - ShellUtils.fastCmdResult(this, "${getKsuDaemonPath()} $args") + ShellUtils.fastCmdResult(this, "$ksuDaemonPath $args") } } else { - ShellUtils.fastCmdResult(getRootShell(), "${getKsuDaemonPath()} $args") + ShellUtils.fastCmdResult("$ksuDaemonPath $args") } } @@ -105,19 +96,15 @@ fun install() { } fun listModules(): String { - val shell = getRootShell() - val out = - shell.newJob().add("${getKsuDaemonPath()} module list").to(ArrayList(), null).exec().out + Shell.cmd("$ksuDaemonPath module list").to(ArrayList(), null).exec().out return out.joinToString("\n").ifBlank { "[]" } } fun getModuleCount(): Int { - val result = listModules() - runCatching { - val array = JSONArray(result) - return array.length() - }.getOrElse { return 0 } + return runCatching { + JSONArray(listModules()).length() + }.getOrDefault(0) } fun getSuperuserCount(): Int { @@ -185,7 +172,7 @@ fun flashModule( this?.copyTo(output) } val cmd = "module install ${file.absolutePath}" - val result = flashWithIO("${getKsuDaemonPath()} $cmd", onStdout, onStderr) + val result = flashWithIO("$ksuDaemonPath $cmd", onStdout, onStderr) Log.i("KernelSU", "install module $uri result: $result") file.delete() @@ -212,7 +199,7 @@ fun runModuleAction( } } - val result = shell.newJob().add("${getKsuDaemonPath()} module action $moduleId") + val result = shell.newJob().add("$ksuDaemonPath module action $moduleId") .to(stdoutCallback, stderrCallback).exec() Log.i("KernelSU", "Module runAction result: $result") @@ -224,7 +211,7 @@ fun restoreBoot( ): Boolean { val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libzakoboot.so") val result = flashWithIO( - "${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot", + "$ksuDaemonPath boot-restore -f --magiskboot $magiskboot", onStdout, onStderr ) @@ -237,7 +224,7 @@ fun uninstallPermanently( ): Boolean { val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libzakoboot.so") val result = - flashWithIO("${getKsuDaemonPath()} uninstall --magiskboot $magiskboot", onStdout, onStderr) + flashWithIO("$ksuDaemonPath uninstall --magiskboot $magiskboot", onStdout, onStderr) onFinish(result.isSuccess, result.code) return result.isSuccess } @@ -312,7 +299,7 @@ fun installBoot( Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) cmd += " -o $downloadsDir" - val result = flashWithIO("${getKsuDaemonPath()} $cmd", onStdout, onStderr) + val result = flashWithIO("$ksuDaemonPath $cmd", onStdout, onStderr) Log.i("KernelSU", "install boot result: ${result.isSuccess}") bootFile?.delete() @@ -324,22 +311,17 @@ fun installBoot( } fun reboot(reason: String = "") { - val shell = getRootShell() if (reason == "recovery") { // KEYCODE_POWER = 26, hide incorrect "Factory data reset" message - ShellUtils.fastCmd(shell, "/system/bin/input keyevent 26") + ShellUtils.fastCmdResult("/system/bin/input keyevent 26") } - ShellUtils.fastCmd(shell, "/system/bin/svc power reboot $reason || /system/bin/reboot $reason") + ShellUtils.fastCmdResult("/system/bin/svc power reboot $reason || /system/bin/reboot $reason") } -fun rootAvailable(): Boolean { - val shell = getRootShell() - return shell.isRoot -} +fun rootAvailable() = Shell.isAppGrantedRoot() == true fun isAbDevice(): Boolean { - val shell = getRootShell() - return ShellUtils.fastCmd(shell, "getprop ro.build.ab_update").trim().toBoolean() + return ShellUtils.fastCmd("getprop ro.build.ab_update").trim().toBoolean() } fun isInitBoot(): Boolean { @@ -347,91 +329,77 @@ fun isInitBoot(): Boolean { } suspend fun getCurrentKmi(): String = withContext(Dispatchers.IO) { - val shell = getRootShell() val cmd = "boot-info current-kmi" - ShellUtils.fastCmd(shell, "${getKsuDaemonPath()} $cmd") + ShellUtils.fastCmd("$ksuDaemonPath $cmd") } suspend fun getSupportedKmis(): List = withContext(Dispatchers.IO) { - val shell = getRootShell() val cmd = "boot-info supported-kmi" - val out = shell.newJob().add("${getKsuDaemonPath()} $cmd").to(ArrayList(), null).exec().out + val out = Shell.cmd("$ksuDaemonPath $cmd").to(ArrayList(), null).exec().out out.filter { it.isNotBlank() }.map { it.trim() } } fun hasMagisk(): Boolean { - val shell = getRootShell(true) - val result = shell.newJob().add("which magisk").exec() - Log.i(TAG, "has magisk: ${result.isSuccess}") - return result.isSuccess + val result = ShellUtils.fastCmdResult("which magisk") + Log.i(TAG, "has magisk: $result") + return result } fun isSepolicyValid(rules: String?): Boolean { if (rules == null) { return true } - val shell = getRootShell() val result = - shell.newJob().add("${getKsuDaemonPath()} sepolicy check '$rules'").to(ArrayList(), null) + Shell.cmd("$ksuDaemonPath sepolicy check '$rules'").to(ArrayList(), null) .exec() return result.isSuccess } fun getSepolicy(pkg: String): String { - val shell = getRootShell() val result = - shell.newJob().add("${getKsuDaemonPath()} profile get-sepolicy $pkg").to(ArrayList(), null) + Shell.cmd("$ksuDaemonPath profile get-sepolicy $pkg").to(ArrayList(), null) .exec() Log.i(TAG, "code: ${result.code}, out: ${result.out}, err: ${result.err}") return result.out.joinToString("\n") } fun setSepolicy(pkg: String, rules: String): Boolean { - val shell = getRootShell() - val result = shell.newJob().add("${getKsuDaemonPath()} profile set-sepolicy $pkg '$rules'") + val result = Shell.cmd("$ksuDaemonPath profile set-sepolicy $pkg '$rules'") .to(ArrayList(), null).exec() Log.i(TAG, "set sepolicy result: ${result.code}") return result.isSuccess } fun listAppProfileTemplates(): List { - val shell = getRootShell() - return shell.newJob().add("${getKsuDaemonPath()} profile list-templates").to(ArrayList(), null) + return Shell.cmd("$ksuDaemonPath profile list-templates").to(ArrayList(), null) .exec().out } fun getAppProfileTemplate(id: String): String { - val shell = getRootShell() - return shell.newJob().add("${getKsuDaemonPath()} profile get-template '${id}'") + return Shell.cmd("$ksuDaemonPath profile get-template '${id}'") .to(ArrayList(), null).exec().out.joinToString("\n") } fun setAppProfileTemplate(id: String, template: String): Boolean { - val shell = getRootShell() val escapedTemplate = template.replace("\"", "\\\"") - val cmd = """${getKsuDaemonPath()} profile set-template "$id" "$escapedTemplate'"""" - return shell.newJob().add(cmd) + val cmd = """$ksuDaemonPath profile set-template "$id" "$escapedTemplate'"""" + return Shell.cmd(cmd) .to(ArrayList(), null).exec().isSuccess } fun deleteAppProfileTemplate(id: String): Boolean { - val shell = getRootShell() - return shell.newJob().add("${getKsuDaemonPath()} profile delete-template '${id}'") + return Shell.cmd("$ksuDaemonPath profile delete-template '${id}'") .to(ArrayList(), null).exec().isSuccess } fun forceStopApp(packageName: String) { - val shell = getRootShell() - val result = shell.newJob().add("am force-stop $packageName").exec() + val result = Shell.cmd("am force-stop $packageName").exec() Log.i(TAG, "force stop $packageName result: $result") } fun launchApp(packageName: String) { - - val shell = getRootShell() val result = - shell.newJob() - .add("cmd package resolve-activity --brief $packageName | tail -n 1 | xargs cmd activity start-activity -n") + Shell.cmd("cmd package resolve-activity --brief $packageName | tail -n 1 | xargs cmd activity start-activity -n") .exec() Log.i(TAG, "launch $packageName result: $result") } @@ -441,131 +409,90 @@ fun restartApp(packageName: String) { launchApp(packageName) } -fun getSuSFSDaemonPath(): String { - return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libzakozakozako.so" +val suSFSDaemonPath by lazy { + "${ksuApp.applicationInfo.nativeLibraryDir}${File.separator}libzakozakozako.so" } fun getSuSFS(): String { - val shell = getRootShell() - val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} support") - return result + return ShellUtils.fastCmd("$suSFSDaemonPath support") } fun getSuSFSVersion(): String { - val shell = getRootShell() - val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} version") - return result + return ShellUtils.fastCmd("$suSFSDaemonPath version") } fun getSuSFSVariant(): String { - val shell = getRootShell() - val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} variant") - return result + return ShellUtils.fastCmd("$suSFSDaemonPath variant") } fun getSuSFSFeatures(): String { - val shell = getRootShell() - val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} features") - return result + return ShellUtils.fastCmd("$suSFSDaemonPath features") } fun susfsSUS_SU_0(): String { - val shell = getRootShell() - val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su 0") - return result + return ShellUtils.fastCmd("$suSFSDaemonPath sus_su 0") } fun susfsSUS_SU_2(): String { - val shell = getRootShell() - val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su 2") - return result + return ShellUtils.fastCmd("$suSFSDaemonPath sus_su 2") } fun susfsSUS_SU_Mode(): String { - val shell = getRootShell() - val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su mode") - return result + return ShellUtils.fastCmd("$suSFSDaemonPath sus_su mode") } -fun getKpmmgrPath(): String { - return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libkpmmgr.so" +val kpmmgrPath by lazy { + "${ksuApp.applicationInfo.nativeLibraryDir}${File.separator}libkpmmgr.so" } fun loadKpmModule(path: String, args: String? = null): String { - val shell = getRootShell() - val cmd = "${getKpmmgrPath()} load $path ${args ?: ""}" - return ShellUtils.fastCmd(shell, cmd) + return ShellUtils.fastCmd("$kpmmgrPath load $path ${args ?: ""}") } fun unloadKpmModule(name: String): String { - val shell = getRootShell() - val cmd = "${getKpmmgrPath()} unload $name" - return ShellUtils.fastCmd(shell, cmd) + return ShellUtils.fastCmd("$kpmmgrPath unload $name") } fun getKpmModuleCount(): Int { - val shell = getRootShell() - val cmd = "${getKpmmgrPath()} num" - val result = ShellUtils.fastCmd(shell, cmd) + val result = ShellUtils.fastCmd("$kpmmgrPath num") return result.trim().toIntOrNull() ?: 0 } -fun runCmd(shell: Shell, cmd: String): String { - return shell.newJob() - .add(cmd) +fun runCmd(cmd: String): String { + return Shell.cmd(cmd) .to(mutableListOf(), null) .exec().out .joinToString("\n") } fun listKpmModules(): String { - val shell = getRootShell() - val cmd = "${getKpmmgrPath()} list" - return try { - runCmd(shell, cmd).trim() - } catch (e: Exception) { - Log.e(TAG, "Failed to list KPM modules", e) - "" - } + return runCmd("$kpmmgrPath list").trim() } fun getKpmModuleInfo(name: String): String { - val shell = getRootShell() - val cmd = "${getKpmmgrPath()} info $name" - return try { - runCmd(shell, cmd).trim() - } catch (e: Exception) { - Log.e(TAG, "Failed to get KPM module info: $name", e) - "" - } + return runCmd("$kpmmgrPath info $name").trim() } fun controlKpmModule(name: String, args: String? = null): Int { - val shell = getRootShell() - val cmd = """${getKpmmgrPath()} control $name "${args ?: ""}"""" - val result = runCmd(shell, cmd) + val result = runCmd("""$kpmmgrPath control $name "${args ?: ""}"""") return result.trim().toIntOrNull() ?: -1 } fun getKpmVersion(): String { - val shell = getRootShell() - val cmd = "${getKpmmgrPath()} version" - val result = ShellUtils.fastCmd(shell, cmd) - return result.trim() + return ShellUtils.fastCmd("$kpmmgrPath version").trim() } fun getZygiskImplement(): String { - val shell = getRootShell() val zygiskPath = "/data/adb/modules/zygisksu" val rezygiskPath = "/data/adb/modules/rezygisk" - val result = if (ShellUtils.fastCmdResult(shell, "test -f $zygiskPath/module.prop && test ! -f $zygiskPath/disable")) { - ShellUtils.fastCmd(shell, "grep '^name=' $zygiskPath/module.prop | cut -d'=' -f2") - } else if (ShellUtils.fastCmdResult(shell, "test -f $rezygiskPath/module.prop && test ! -f $rezygiskPath/disable")) { - ShellUtils.fastCmd(shell, "grep '^name=' $rezygiskPath/module.prop | cut -d'=' -f2") - } else { - "None" - } + val result = when { + SuFile(zygiskPath, "module.prop").exists() && !SuFile(zygiskPath, "disable").exists() -> + ShellUtils.fastCmd("grep '^name=' $zygiskPath/module.prop | cut -d'=' -f2") + SuFile(rezygiskPath, "module.prop").exists() && !SuFile(rezygiskPath, "disable").exists() -> + ShellUtils.fastCmd("grep '^name=' $rezygiskPath/module.prop | cut -d'=' -f2") + else -> "None" + }.trim() Log.i(TAG, "Zygisk implement: $result") return result } diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/LogEvent.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/LogEvent.kt index 758cc2b8..fd1885e0 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/LogEvent.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/LogEvent.kt @@ -3,9 +3,10 @@ package com.sukisu.ultra.ui.util import android.content.Context import android.os.Build import android.system.Os -import com.topjohnwu.superuser.ShellUtils import com.sukisu.ultra.Natives import com.sukisu.ultra.ui.screen.getManagerVersion +import com.topjohnwu.superuser.Shell +import com.topjohnwu.superuser.ShellUtils import java.io.File import java.io.FileWriter import java.io.PrintWriter @@ -38,30 +39,28 @@ fun getBugreportFile(context: Context): File { val bootConfig = File(bugreportDir, "boot_config.txt") val kernelConfig = File(bugreportDir, "defconfig.gz") - val shell = getRootShell(true) + Shell.cmd("dmesg > ${dmesgFile.absolutePath}").exec() + Shell.cmd("logcat -d > ${logcatFile.absolutePath}").exec() + Shell.cmd("tar -czf ${tombstonesFile.absolutePath} -C /data/tombstones .").exec() + Shell.cmd("tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .").exec() + Shell.cmd("tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .").exec() + Shell.cmd("tar -czf ${diagFile.absolutePath} -C /data/vendor/diag . --exclude=./minidump.gz").exec() + Shell.cmd("tar -czf ${oplusFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec() + Shell.cmd("tar -czf ${bootlogFile.absolutePath} -C /data/adb/ksu/log .").exec() - shell.newJob().add("dmesg > ${dmesgFile.absolutePath}").exec() - shell.newJob().add("logcat -d > ${logcatFile.absolutePath}").exec() - shell.newJob().add("tar -czf ${tombstonesFile.absolutePath} -C /data/tombstones .").exec() - shell.newJob().add("tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .").exec() - shell.newJob().add("tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .").exec() - shell.newJob().add("tar -czf ${diagFile.absolutePath} -C /data/vendor/diag . --exclude=./minidump.gz").exec() - shell.newJob().add("tar -czf ${oplusFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec() - shell.newJob().add("tar -czf ${bootlogFile.absolutePath} -C /data/adb/ksu/log .").exec() + Shell.cmd("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec() + Shell.cmd("cat /proc/filesystems > ${fileSystemsFile.absolutePath}").exec() + Shell.cmd("busybox tree /data/adb > ${adbFileTree.absolutePath}").exec() + Shell.cmd("ls -alRZ /data/adb > ${adbFileDetails.absolutePath}").exec() + Shell.cmd("du -sh /data/adb/ksu/* > ${ksuFileSize.absolutePath}").exec() + Shell.cmd("cp /data/system/packages.list ${appListFile.absolutePath}").exec() + Shell.cmd("getprop > ${propFile.absolutePath}").exec() + Shell.cmd("cp /data/adb/ksu/.allowlist ${allowListFile.absolutePath}").exec() + Shell.cmd("cp /proc/modules ${procModules.absolutePath}").exec() + Shell.cmd("cp /proc/bootconfig ${bootConfig.absolutePath}").exec() + Shell.cmd("cp /proc/config.gz ${kernelConfig.absolutePath}").exec() - shell.newJob().add("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec() - shell.newJob().add("cat /proc/filesystems > ${fileSystemsFile.absolutePath}").exec() - shell.newJob().add("busybox tree /data/adb > ${adbFileTree.absolutePath}").exec() - shell.newJob().add("ls -alRZ /data/adb > ${adbFileDetails.absolutePath}").exec() - shell.newJob().add("du -sh /data/adb/ksu/* > ${ksuFileSize.absolutePath}").exec() - shell.newJob().add("cp /data/system/packages.list ${appListFile.absolutePath}").exec() - shell.newJob().add("getprop > ${propFile.absolutePath}").exec() - shell.newJob().add("cp /data/adb/ksu/.allowlist ${allowListFile.absolutePath}").exec() - shell.newJob().add("cp /proc/modules ${procModules.absolutePath}").exec() - shell.newJob().add("cp /proc/bootconfig ${bootConfig.absolutePath}").exec() - shell.newJob().add("cp /proc/config.gz ${kernelConfig.absolutePath}").exec() - - val selinux = ShellUtils.fastCmd(shell, "getenforce") + val selinux = ShellUtils.fastCmd("getenforce") // basic information val buildInfo = File(bugreportDir, "basic.txt") @@ -102,9 +101,9 @@ fun getBugreportFile(context: Context): File { val targetFile = File(context.cacheDir, "KernelSU_bugreport_${current}.tar.gz") - shell.newJob().add("tar czf ${targetFile.absolutePath} -C ${bugreportDir.absolutePath} .").exec() - shell.newJob().add("rm -rf ${bugreportDir.absolutePath}").exec() - shell.newJob().add("chmod 0644 ${targetFile.absolutePath}").exec() + Shell.cmd("tar czf ${targetFile.absolutePath} -C ${bugreportDir.absolutePath} .").exec() + Shell.cmd("rm -rf ${bugreportDir.absolutePath}").exec() + Shell.cmd("chmod 0644 ${targetFile.absolutePath}").exec() return targetFile } diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleModify.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleModify.kt index 120939a3..190ce9c4 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleModify.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleModify.kt @@ -9,17 +9,16 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.platform.LocalContext +import com.sukisu.ultra.R import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import com.sukisu.ultra.R import java.io.BufferedReader import java.io.IOException import java.io.InputStreamReader import java.text.SimpleDateFormat -import java.util.Date -import java.util.Locale +import java.util.* object ModuleModify { @Composable @@ -442,8 +441,4 @@ object ModuleModify { type = "application/octet-stream" } } - - private fun reboot() { - Runtime.getRuntime().exec(arrayOf("su", "-c", "reboot")) - } } \ No newline at end of file diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleUtils.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleUtils.kt index 49e86deb..230b99f5 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleUtils.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleUtils.kt @@ -3,13 +3,13 @@ package com.sukisu.ultra.ui.util import android.content.Context import android.content.Intent import android.net.Uri +import android.util.Log +import com.sukisu.ultra.R import java.io.BufferedReader +import java.io.IOException import java.io.InputStreamReader import java.nio.charset.StandardCharsets import java.util.zip.ZipInputStream -import com.sukisu.ultra.R -import android.util.Log -import java.io.IOException object ModuleUtils { private const val TAG = "ModuleUtils" @@ -108,10 +108,7 @@ object ModuleUtils { return try { - val inputStream = context.contentResolver.openInputStream(uri) - if (inputStream == null) { - return null - } + val inputStream = context.contentResolver.openInputStream(uri) ?: return null val zipInputStream = ZipInputStream(inputStream) var entry = zipInputStream.nextEntry diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleVerificationManager.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleVerificationManager.kt index 9e70c40b..6f7ce6e6 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleVerificationManager.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleVerificationManager.kt @@ -4,6 +4,7 @@ import android.content.Context import android.net.Uri import android.util.Log import com.sukisu.ultra.Natives +import com.topjohnwu.superuser.Shell import java.io.File import java.io.FileOutputStream @@ -124,18 +125,17 @@ object ModuleVerificationManager { // 为指定模块创建验证标志文件 fun createVerificationFlag(moduleId: String): Boolean { return try { - val shell = getRootShell() val flagFilePath = "$VERIFICATION_FLAGS_DIR/$moduleId" // 确保目录存在 val createDirCommand = "mkdir -p '$VERIFICATION_FLAGS_DIR'" - shell.newJob().add(createDirCommand).exec() + Shell.cmd(createDirCommand).exec() // 创建验证标志文件,写入验证时间戳 val timestamp = System.currentTimeMillis() val command = "echo '$timestamp' > '$flagFilePath'" - val result = shell.newJob().add(command).exec() + val result = Shell.cmd(command).exec() if (result.isSuccess) { Log.d(TAG, "验证标志文件创建成功: $flagFilePath") @@ -152,11 +152,10 @@ object ModuleVerificationManager { fun removeVerificationFlag(moduleId: String): Boolean { return try { - val shell = getRootShell() val flagFilePath = "$VERIFICATION_FLAGS_DIR/$moduleId" val command = "rm -f '$flagFilePath'" - val result = shell.newJob().add(command).exec() + val result = Shell.cmd(command).exec() if (result.isSuccess) { Log.d(TAG, "验证标志文件移除成功: $flagFilePath") @@ -173,11 +172,10 @@ object ModuleVerificationManager { fun getVerificationTimestamp(moduleId: String): Long { return try { - val shell = getRootShell() val flagFilePath = "$VERIFICATION_FLAGS_DIR/$moduleId" val command = "cat '$flagFilePath' 2>/dev/null || echo '0'" - val result = shell.newJob().add(command).to(ArrayList(), null).exec() + val result = Shell.cmd(command).to(ArrayList(), null).exec() if (result.isSuccess && result.out.isNotEmpty()) { val timestampStr = result.out.firstOrNull()?.trim() ?: "0" @@ -195,12 +193,11 @@ object ModuleVerificationManager { if (moduleIds.isEmpty()) return emptyMap() return try { - val shell = getRootShell() val result = mutableMapOf() // 确保目录存在 val createDirCommand = "mkdir -p '$VERIFICATION_FLAGS_DIR'" - shell.newJob().add(createDirCommand).exec() + Shell.cmd(createDirCommand).exec() // 批量检查所有模块的验证标志文件 val commands = moduleIds.map { moduleId -> @@ -208,7 +205,7 @@ object ModuleVerificationManager { } val command = commands.joinToString(" && ") - val shellResult = shell.newJob().add(command).to(ArrayList(), null).exec() + val shellResult = Shell.cmd(command).to(ArrayList(), null).exec() if (shellResult.isSuccess) { shellResult.out.forEach { line -> diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SELinuxChecker.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SELinuxChecker.kt index dff51722..b7e5216f 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SELinuxChecker.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SELinuxChecker.kt @@ -1,31 +1,19 @@ package com.sukisu.ultra.ui.util import android.content.Context -import com.topjohnwu.superuser.Shell import com.sukisu.ultra.R +import com.topjohnwu.superuser.io.SuFile -fun getSELinuxStatus(context: Context): String { - val shell = Shell.Builder.create().build("sh") - val list = ArrayList() - - val result = shell.use { - it.newJob().add("getenforce").to(list, list).exec() - } - - val output = list.joinToString("\n").trim() - - return if (result.isSuccess) { - when (output) { - "Enforcing" -> context.getString(R.string.selinux_status_enforcing) - "Permissive" -> context.getString(R.string.selinux_status_permissive) - "Disabled" -> context.getString(R.string.selinux_status_disabled) +fun getSELinuxStatus(context: Context) = SuFile("/sys/fs/selinux/enforce").run { + when { + !exists() -> context.getString(R.string.selinux_status_disabled) + !isFile -> context.getString(R.string.selinux_status_unknown) + !canRead() -> context.getString(R.string.selinux_status_enforcing) + else -> when (runCatching { newInputStream() }.getOrNull()?.bufferedReader() + ?.use { it.runCatching { readLine() }.getOrNull()?.trim()?.toIntOrNull() }) { + 1 -> context.getString(R.string.selinux_status_enforcing) + 0 -> context.getString(R.string.selinux_status_permissive) else -> context.getString(R.string.selinux_status_unknown) } - } else { - if (output.contains("Permission denied")) { - context.getString(R.string.selinux_status_enforcing) - } else { - context.getString(R.string.selinux_status_unknown) - } } } \ No newline at end of file diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt index 0da7793e..40e6264e 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt @@ -7,22 +7,17 @@ import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.util.Log import android.widget.Toast +import androidx.core.content.edit import com.dergoogler.mmrl.platform.Platform.Companion.context import com.sukisu.ultra.Natives import com.sukisu.ultra.R +import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel import com.topjohnwu.superuser.Shell -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import kotlinx.coroutines.withContext +import kotlinx.coroutines.* +import org.json.JSONObject import java.io.File import java.io.FileOutputStream import java.io.IOException -import androidx.core.content.edit -import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import org.json.JSONObject import java.text.SimpleDateFormat import java.util.* @@ -430,12 +425,10 @@ object SuSFSManager { async(Dispatchers.IO) { val dataPath = "$MEDIA_DATA_PATH/${appInfo.packageName}" val exists = try { - val shell = getRootShell() val outputList = mutableListOf() val errorList = mutableListOf() - val result = shell.newJob() - .add("[ -d \"$dataPath\" ] && echo 'exists' || echo 'not_exists'") + val result = Shell.cmd("[ -d \"$dataPath\" ] && echo 'exists' || echo 'not_exists'") .to(outputList, errorList) .exec() diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/HomeViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/HomeViewModel.kt index 8ccf7c82..838c2298 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/HomeViewModel.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/HomeViewModel.kt @@ -8,6 +8,7 @@ import android.util.Log import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.core.content.edit import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.dergoogler.mmrl.platform.Platform.Companion.context @@ -22,7 +23,6 @@ import com.sukisu.ultra.ui.util.module.LatestVersionInfo import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import androidx.core.content.edit class HomeViewModel : ViewModel() { companion object { diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/KpmViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/KpmViewModel.kt index 4d2948a1..36c5b437 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/KpmViewModel.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/KpmViewModel.kt @@ -6,10 +6,10 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.sukisu.ultra.ui.util.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import com.sukisu.ultra.ui.util.* /** * @author ShirkNeko diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt index f8dfe2e0..fef0f154 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt @@ -7,26 +7,26 @@ import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue +import androidx.core.content.edit import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.dergoogler.mmrl.platform.model.ModuleConfig import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig +import com.sukisu.ultra.ui.util.HanziToPinyin +import com.sukisu.ultra.ui.util.ModuleVerificationManager +import com.sukisu.ultra.ui.util.listModules +import com.topjohnwu.superuser.Shell import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import com.sukisu.ultra.ui.util.HanziToPinyin -import com.sukisu.ultra.ui.util.listModules -import com.sukisu.ultra.ui.util.getRootShell -import com.sukisu.ultra.ui.util.ModuleVerificationManager import kotlinx.coroutines.withContext import org.json.JSONArray import org.json.JSONObject import java.text.Collator import java.text.DecimalFormat -import java.util.Locale +import java.util.* import java.util.concurrent.TimeUnit import kotlin.math.log10 import kotlin.math.pow -import androidx.core.content.edit /** * @author ShirkNeko @@ -452,9 +452,8 @@ class ModuleSizeCache(context: Context) { */ private fun calculateModuleFolderSize(dirId: String): Long { return try { - val shell = getRootShell() val command = "du -sb /data/adb/modules/$dirId" - val result = shell.newJob().add(command).to(ArrayList(), null).exec() + val result = Shell.cmd(command).to(ArrayList(), null).exec() if (result.isSuccess && result.out.isNotEmpty()) { val sizeStr = result.out.firstOrNull()?.split("\t")?.firstOrNull() diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/SuperUserViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/SuperUserViewModel.kt index b3ac1eb8..0bd03203 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/SuperUserViewModel.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/SuperUserViewModel.kt @@ -1,43 +1,29 @@ package com.sukisu.ultra.ui.viewmodel -import android.content.ComponentName -import android.content.Context -import android.content.Intent -import android.content.ServiceConnection -import android.content.SharedPreferences +import android.content.* import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.os.IBinder import android.os.Parcelable import android.os.SystemClock import android.util.Log -import androidx.compose.runtime.derivedStateOf -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* +import androidx.core.content.edit import androidx.lifecycle.ViewModel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import kotlinx.coroutines.supervisorScope +import com.sukisu.ultra.Natives +import com.sukisu.ultra.ksuApp +import com.sukisu.ultra.ui.KsuService +import com.sukisu.ultra.ui.util.HanziToPinyin +import com.topjohnwu.superuser.Shell +import kotlinx.coroutines.* import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.parcelize.Parcelize -import com.sukisu.ultra.Natives -import com.sukisu.ultra.ksuApp -import com.sukisu.ultra.ui.util.HanziToPinyin import java.text.Collator import java.util.* +import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.ThreadPoolExecutor import java.util.concurrent.TimeUnit -import java.util.concurrent.LinkedBlockingQueue -import androidx.core.content.edit -import com.sukisu.ultra.ui.KsuService -import com.sukisu.ultra.ui.util.KsuCli -import com.topjohnwu.superuser.Shell -import kotlinx.coroutines.asCoroutineDispatcher import kotlin.coroutines.resume import kotlin.coroutines.suspendCoroutine @@ -428,8 +414,7 @@ class SuperUserViewModel : ViewModel() { Shell.EXECUTOR, connection ) - val shell = KsuCli.SHELL - task?.let { shell.execTask(it) } + task?.let { Shell.getShell().execTask(it) } } catch (e: Exception) { Log.e(TAG, "Failed to bind KsuService", e) continuation.resume(null) diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/TemplateViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/TemplateViewModel.kt index 38f7577d..7aa5b945 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/TemplateViewModel.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/TemplateViewModel.kt @@ -7,21 +7,21 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import kotlinx.parcelize.Parcelize import com.sukisu.ultra.Natives import com.sukisu.ultra.profile.Capabilities import com.sukisu.ultra.profile.Groups import com.sukisu.ultra.ui.util.getAppProfileTemplate import com.sukisu.ultra.ui.util.listAppProfileTemplates import com.sukisu.ultra.ui.util.setAppProfileTemplate +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import kotlinx.parcelize.Parcelize import okhttp3.OkHttpClient import okhttp3.Request import org.json.JSONArray import org.json.JSONObject import java.text.Collator -import java.util.Locale +import java.util.* import java.util.concurrent.TimeUnit diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/KsuLibSuProvider.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/KsuLibSuProvider.kt index 0b4e76b2..7650defe 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/KsuLibSuProvider.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/KsuLibSuProvider.kt @@ -1,13 +1,13 @@ package com.sukisu.ultra.ui.webui import android.content.ServiceConnection -import android.util.Log import android.content.pm.PackageInfo +import android.util.Log import com.dergoogler.mmrl.platform.Platform import com.dergoogler.mmrl.platform.model.IProvider import com.dergoogler.mmrl.platform.model.PlatformIntent -import com.sukisu.ultra.ksuApp import com.sukisu.ultra.Natives +import com.sukisu.ultra.ksuApp import com.topjohnwu.superuser.ipc.RootService import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/SuFilePathHandler.java b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/SuFilePathHandler.java index 699c3706..263aa953 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/SuFilePathHandler.java +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/SuFilePathHandler.java @@ -3,11 +3,9 @@ package com.sukisu.ultra.ui.webui; import android.content.Context; import android.util.Log; import android.webkit.WebResourceResponse; - import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import androidx.webkit.WebViewAssetLoader; - import com.topjohnwu.superuser.Shell; import com.topjohnwu.superuser.io.SuFile; import com.topjohnwu.superuser.io.SuFileInputStream; diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIActivity.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIActivity.kt index 2aa03a0f..f1b77734 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIActivity.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIActivity.kt @@ -16,16 +16,14 @@ import androidx.core.view.WindowInsetsCompat import androidx.core.view.updateLayoutParams import androidx.webkit.WebViewAssetLoader import com.dergoogler.mmrl.platform.model.ModId -import com.topjohnwu.superuser.Shell +import com.dergoogler.mmrl.webui.interfaces.WXOptions import com.sukisu.ultra.ui.util.createRootShell import java.io.File -import com.dergoogler.mmrl.webui.interfaces.WXOptions @SuppressLint("SetJavaScriptEnabled") class WebUIActivity : ComponentActivity() { - private lateinit var webviewInterface: WebViewInterface - - private var rootShell: Shell? = null + private val rootShell by lazy { createRootShell(true) } + private var webView = null as WebView? override fun onCreate(savedInstanceState: Bundle?) { @@ -37,8 +35,8 @@ class WebUIActivity : ComponentActivity() { super.onCreate(savedInstanceState) - val moduleId = intent.getStringExtra("id")!! - val name = intent.getStringExtra("name")!! + val moduleId = intent.getStringExtra("id") ?: finishAndRemoveTask().let { return } + val name = intent.getStringExtra("name") ?: finishAndRemoveTask().let { return } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { @Suppress("DEPRECATION") setTaskDescription(ActivityManager.TaskDescription("SukiSU-Ultra - $name")) @@ -53,7 +51,6 @@ class WebUIActivity : ComponentActivity() { val moduleDir = "/data/adb/modules/${moduleId}" val webRoot = File("${moduleDir}/webroot") - val rootShell = createRootShell(true).also { this.rootShell = it } val webViewAssetLoader = WebViewAssetLoader.Builder() .setDomain("mui.kernelsu.org") .addPathHandler( @@ -72,6 +69,8 @@ class WebUIActivity : ComponentActivity() { } val webView = WebView(this).apply { + webView = this + ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets -> val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars()) view.updateLayoutParams { @@ -85,8 +84,7 @@ class WebUIActivity : ComponentActivity() { settings.javaScriptEnabled = true settings.domStorageEnabled = true settings.allowFileAccess = false - webviewInterface = WebViewInterface(WXOptions(this@WebUIActivity, this, ModId(moduleId))) - addJavascriptInterface(webviewInterface, "ksu") + addJavascriptInterface(WebViewInterface(WXOptions(this@WebUIActivity, this, ModId(moduleId))), "ksu") setWebViewClient(webViewClient) loadUrl("https://mui.kernelsu.org/index.html") } @@ -95,7 +93,13 @@ class WebUIActivity : ComponentActivity() { } override fun onDestroy() { + rootShell.runCatching { close() } + webView?.apply { + stopLoading() + removeAllViews() + destroy() + webView = null + } super.onDestroy() - runCatching { rootShell?.close() } } } \ No newline at end of file diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIXActivity.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIXActivity.kt index bfe7ffed..85781a92 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIXActivity.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIXActivity.kt @@ -8,11 +8,7 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.lifecycle.lifecycleScope import com.dergoogler.mmrl.platform.Platform import com.dergoogler.mmrl.platform.model.ModId diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebViewInterface.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebViewInterface.kt index c4f9d4d7..23351042 100644 --- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebViewInterface.kt +++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebViewInterface.kt @@ -12,18 +12,16 @@ import androidx.core.view.WindowInsetsControllerCompat import com.dergoogler.mmrl.webui.interfaces.WXInterface import com.dergoogler.mmrl.webui.interfaces.WXOptions import com.dergoogler.mmrl.webui.model.JavaScriptInterface +import com.sukisu.ultra.ui.util.* import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.internal.UiThreadHandler -import com.sukisu.ultra.ui.util.createRootShell -import com.sukisu.ultra.ui.util.listModules -import com.sukisu.ultra.ui.util.withNewRootShell import org.json.JSONArray import org.json.JSONObject -import com.sukisu.ultra.ui.util.* import java.io.File import java.util.concurrent.CompletableFuture +@Suppress("unused") class WebViewInterface( wxOptions: WXOptions, ) : WXInterface(wxOptions) { @@ -68,56 +66,56 @@ class WebViewInterface( options: String?, callbackFunc: String ) { - val finalCommand = StringBuilder() - processOptions(finalCommand, options) - finalCommand.append(cmd) + val finalCommand = buildString { + processOptions(this, options) + append(cmd) + } val result = withNewRootShell(true) { - newJob().add(finalCommand.toString()).to(ArrayList(), ArrayList()).exec() + newJob().add(finalCommand).to(ArrayList(), ArrayList()).exec() } val stdout = result.out.joinToString(separator = "\n") val stderr = result.err.joinToString(separator = "\n") val jsCode = - "javascript: (function() { try { ${callbackFunc}(${result.code}, ${ + "(function() { try { ${callbackFunc}(${result.code}, ${ JSONObject.quote( stdout ) }, ${JSONObject.quote(stderr)}); } catch(e) { console.error(e); } })();" webView.post { - webView.loadUrl(jsCode) + webView.evaluateJavascript(jsCode, null) } } @JavascriptInterface fun spawn(command: String, args: String, options: String?, callbackFunc: String) { - val finalCommand = StringBuilder() + val finalCommand = buildString { + processOptions(this, options) - processOptions(finalCommand, options) - - if (!TextUtils.isEmpty(args)) { - finalCommand.append(command).append(" ") - JSONArray(args).let { argsArray -> - for (i in 0 until argsArray.length()) { - finalCommand.append(argsArray.getString(i)) - finalCommand.append(" ") + if (!TextUtils.isEmpty(args)) { + append(command).append(" ") + JSONArray(args).let { argsArray -> + for (i in 0 until argsArray.length()) { + append("${argsArray.getString(i)} ") + } } + } else { + append(command) } - } else { - finalCommand.append(command) } val shell = createRootShell(true) val emitData = fun(name: String, data: String) { val jsCode = - "javascript: (function() { try { ${callbackFunc}.${name}.emit('data', ${ + "(function() { try { ${callbackFunc}.${name}.emit('data', ${ JSONObject.quote( data ) }); } catch(e) { console.error('emitData', e); } })();" webView.post { - webView.loadUrl(jsCode) + webView.evaluateJavascript(jsCode, null) } } @@ -133,21 +131,21 @@ class WebViewInterface( } } - val future = shell.newJob().add(finalCommand.toString()).to(stdout, stderr).enqueue() + val future = shell.newJob().add(finalCommand).to(stdout, stderr).enqueue() val completableFuture = CompletableFuture.supplyAsync { future.get() } completableFuture.thenAccept { result -> val emitExitCode = - "javascript: (function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \${e}`); } })();" + "(function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \${e}`); } })();" webView.post { - webView.loadUrl(emitExitCode) + webView.evaluateJavascript(emitExitCode, null) } if (result.code != 0) { val emitErrCode = - "javascript: (function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${ + "(function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${ JSONObject.quote( result.err.joinToString( "\n" @@ -155,7 +153,7 @@ class WebViewInterface( ) };${callbackFunc}.emit('error', err); } catch(e) { console.error('emitErr', e); } })();" webView.post { - webView.loadUrl(emitErrCode) + webView.evaluateJavascript(emitErrCode, null) } } }.whenComplete { _, _ -> @@ -208,12 +206,12 @@ class WebViewInterface( // =================== KPM支持 ============================= @JavascriptInterface - fun listAllKpm() : String { + fun listAllKpm(): String { return listKpmModules() } @JavascriptInterface - fun controlKpm(name: String, args: String) : Int { + fun controlKpm(name: String, args: String): Int { return controlKpmModule(name, args) } } diff --git a/manager/app/src/main/java/io/sukisu/ultra/UltraShellHelper.java b/manager/app/src/main/java/io/sukisu/ultra/UltraShellHelper.java index f829f614..68b85228 100644 --- a/manager/app/src/main/java/io/sukisu/ultra/UltraShellHelper.java +++ b/manager/app/src/main/java/io/sukisu/ultra/UltraShellHelper.java @@ -1,15 +1,13 @@ package io.sukisu.ultra; -import java.util.ArrayList; +import com.topjohnwu.superuser.Shell; -import com.sukisu.ultra.ui.util.KsuCli; +import java.util.ArrayList; public class UltraShellHelper { public static String runCmd(String cmds) { StringBuilder sb = new StringBuilder(); - for(String str : KsuCli.INSTANCE.getGLOBAL_MNT_SHELL() - .newJob() - .add(cmds) + for(String str : Shell.cmd(cmds) .to(new ArrayList<>(), null) .exec() .getOut()) { @@ -18,11 +16,6 @@ public class UltraShellHelper { return sb.toString(); } - public static boolean isPathExists(String path) { - String result = runCmd("test -f '" + path + "' && echo 'exists'"); - return result.contains("exists"); - } - public static void CopyFileTo(String path, String target) { runCmd("cp -f '" + path + "' '" + target + "' 2>&1"); } diff --git a/manager/app/src/main/java/io/sukisu/ultra/UltraToolInstall.java b/manager/app/src/main/java/io/sukisu/ultra/UltraToolInstall.java index 3532915e..d6501b9e 100644 --- a/manager/app/src/main/java/io/sukisu/ultra/UltraToolInstall.java +++ b/manager/app/src/main/java/io/sukisu/ultra/UltraToolInstall.java @@ -1,5 +1,7 @@ package io.sukisu.ultra; +import com.topjohnwu.superuser.io.SuFile; + import static com.sukisu.ultra.ui.util.KsuCliKt.getKpmmgrPath; import static com.sukisu.ultra.ui.util.KsuCliKt.getSuSFSDaemonPath; @@ -7,15 +9,17 @@ public class UltraToolInstall { private static final String OUTSIDE_KPMMGR_PATH = "/data/adb/ksu/bin/kpmmgr"; private static final String OUTSIDE_SUSFSD_PATH = "/data/adb/ksu/bin/susfsd"; public static void tryToInstall() { - String kpmmgrPath = getKpmmgrPath(); - if (UltraShellHelper.isPathExists(OUTSIDE_KPMMGR_PATH)) { - UltraShellHelper.CopyFileTo(kpmmgrPath, OUTSIDE_KPMMGR_PATH); - UltraShellHelper.runCmd("chmod a+rx " + OUTSIDE_KPMMGR_PATH); + SuFile KpmmgrFile = new SuFile(OUTSIDE_KPMMGR_PATH); + if (KpmmgrFile.exists()) { + UltraShellHelper.CopyFileTo(getKpmmgrPath(), OUTSIDE_KPMMGR_PATH); + boolean _ = KpmmgrFile.setReadable(true, false); + boolean _ = KpmmgrFile.setExecutable(true, false); } - String SuSFSDaemonPath = getSuSFSDaemonPath(); - if (UltraShellHelper.isPathExists(OUTSIDE_SUSFSD_PATH)) { - UltraShellHelper.CopyFileTo(SuSFSDaemonPath, OUTSIDE_SUSFSD_PATH); - UltraShellHelper.runCmd("chmod a+rx " + OUTSIDE_SUSFSD_PATH); + SuFile SuSFSDaemonFile = new SuFile(OUTSIDE_SUSFSD_PATH); + if (SuSFSDaemonFile.exists()) { + UltraShellHelper.CopyFileTo(getSuSFSDaemonPath(), OUTSIDE_SUSFSD_PATH); + boolean _ = SuSFSDaemonFile.setReadable(true, false); + boolean _ = SuSFSDaemonFile.setExecutable(true, false); } } } diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/component/BottomBar.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/component/BottomBar.kt index c0217eed..14e0c11c 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/component/BottomBar.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/component/BottomBar.kt @@ -1,30 +1,28 @@ package zako.zako.zako.zakoui.activity.component import android.annotation.SuppressLint +import androidx.compose.foundation.layout.* import androidx.compose.material3.* -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.navigation.NavHostController +import com.ramcosta.composedestinations.generated.NavGraphs +import com.ramcosta.composedestinations.spec.RouteOrDirection import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator -import com.ramcosta.composedestinations.spec.RouteOrDirection -import com.ramcosta.composedestinations.generated.NavGraphs import com.sukisu.ultra.Natives import com.sukisu.ultra.ksuApp import com.sukisu.ultra.ui.MainActivity -import zako.zako.zako.zakoui.activity.util.AppData -import zako.zako.zako.zakoui.activity.util.AppData.getKpmVersionUse import com.sukisu.ultra.ui.screen.BottomBarDestination import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha import com.sukisu.ultra.ui.theme.CardConfig.cardElevation -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.WindowInsetsSides -import androidx.compose.foundation.layout.only -import androidx.compose.foundation.layout.navigationBars +import zako.zako.zako.zakoui.activity.util.AppData import zako.zako.zako.zakoui.activity.util.AppData.DataRefreshManager +import zako.zako.zako.zakoui.activity.util.AppData.getKpmVersionUse @SuppressLint("ContextCastToActivity") @OptIn(ExperimentalMaterial3Api::class) diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AnimatedBottomBar.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AnimatedBottomBar.kt index 51e7f64d..3d364e48 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AnimatedBottomBar.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AnimatedBottomBar.kt @@ -1,10 +1,6 @@ package zako.zako.zako.zakoui.activity.util -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically +import androidx.compose.animation.* import androidx.compose.runtime.Composable object AnimatedBottomBar { diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AppData.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AppData.kt index 54fea9d1..50f51368 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AppData.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AppData.kt @@ -1,11 +1,7 @@ package zako.zako.zako.zakoui.activity.util import com.sukisu.ultra.Natives -import com.sukisu.ultra.ui.util.getKpmModuleCount -import com.sukisu.ultra.ui.util.getKpmVersion -import com.sukisu.ultra.ui.util.getModuleCount -import com.sukisu.ultra.ui.util.getSuperuserCount -import com.sukisu.ultra.ui.util.rootAvailable +import com.sukisu.ultra.ui.util.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -84,13 +80,6 @@ object AppData { } } - /** - * 检查是否具有管理员权限 - */ - fun isManager(packageName: String): Boolean { - return Natives.becomeManager(packageName) - } - /** * 检查是否是完整功能模式 */ diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/DataRefreshUtils.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/DataRefreshUtils.kt index 0e9bd72f..e09b1949 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/DataRefreshUtils.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/DataRefreshUtils.kt @@ -3,12 +3,12 @@ package zako.zako.zako.zakoui.activity.util import android.content.Context import androidx.lifecycle.LifecycleCoroutineScope import com.sukisu.ultra.ui.MainActivity -import zako.zako.zako.zakoui.activity.util.AppData.DataRefreshManager import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.isActive import kotlinx.coroutines.launch +import zako.zako.zako.zakoui.activity.util.AppData.DataRefreshManager object DataRefreshUtils { diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/LocaleUtils.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/LocaleUtils.kt index 9ccd08b4..50debbc8 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/LocaleUtils.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/LocaleUtils.kt @@ -4,7 +4,7 @@ import android.annotation.SuppressLint import android.content.Context import android.content.res.Configuration import android.os.Build -import java.util.Locale +import java.util.* object LocaleUtils { diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt index 4faff202..1fb67a71 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt @@ -6,7 +6,9 @@ import android.content.Context import android.net.Uri import androidx.documentfile.provider.DocumentFile import com.sukisu.ultra.R +import com.sukisu.ultra.ui.util.rootAvailable import com.sukisu.ultra.utils.AssetsUtil +import com.topjohnwu.superuser.Shell import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -131,7 +133,7 @@ class HorizonKernelWorker( if (isAbDevice && slot != null) { state.updateStep(context.getString(R.string.horizon_getting_original_slot)) state.updateProgress(0.72f) - originalSlot = runCommandGetOutput(true, "getprop ro.boot.slot_suffix") + originalSlot = runCommandGetOutput("getprop ro.boot.slot_suffix") state.updateStep(context.getString(R.string.horizon_setting_target_slot)) state.updateProgress(0.74f) @@ -165,13 +167,11 @@ class HorizonKernelWorker( // 检查设备是否为AB分区设备 private fun isAbDevice(): Boolean { - val abUpdate = runCommandGetOutput(true, "getprop ro.build.ab_update")?.trim() ?: "" - if (abUpdate.equals("false", ignoreCase = true) || abUpdate.isEmpty()) { - return false - } + val abUpdate = runCommandGetOutput("getprop ro.build.ab_update") + if (!abUpdate.toBoolean()) return false - val slotSuffix = runCommandGetOutput(true, "getprop ro.boot.slot_suffix") - return !slotSuffix.isNullOrEmpty() + val slotSuffix = runCommandGetOutput("getprop ro.boot.slot_suffix") + return slotSuffix.isNotEmpty() } private fun cleanup() { @@ -195,11 +195,10 @@ class HorizonKernelWorker( } } - @SuppressLint("StringFormatInvalid") private fun patch() { - val kernelVersion = runCommandGetOutput(true, "cat /proc/version") + val kernelVersion = runCommandGetOutput("cat /proc/version") val versionRegex = """\d+\.\d+\.\d+""".toRegex() - val version = kernelVersion?.let { versionRegex.find(it) }?.value ?: "" + val version = kernelVersion.let { versionRegex.find(it) }?.value ?: "" val toolName = if (version.isNotEmpty()) { val parts = version.split('.') if (parts.size >= 2) { @@ -286,28 +285,7 @@ class HorizonKernelWorker( } } - private fun runCommandGetOutput(su: Boolean, cmd: String): String? { - val shell = if (su) "su" else "sh" - val process = Runtime.getRuntime().exec(arrayOf(shell, "-c", cmd)) - - return try { - process.inputStream.bufferedReader().use { reader -> - reader.readText().trim() - } - } catch (_: Exception) { - "" - } finally { - process.destroy() - } - } - - private fun rootAvailable(): Boolean { - return try { - val process = Runtime.getRuntime().exec("su -c true") - val exitValue = process.waitFor() - exitValue == 0 - } catch (_: Exception) { - false - } + private fun runCommandGetOutput(cmd: String): String { + return Shell.cmd(cmd).exec().out.joinToString("\n").trim() } } diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/screen/KernelFlash.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/screen/KernelFlash.kt index 0c125c1d..50a94e24 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/screen/KernelFlash.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/screen/KernelFlash.kt @@ -19,6 +19,8 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.key import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -29,21 +31,20 @@ import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.sukisu.ultra.R -import zako.zako.zako.zakoui.flash.HorizonKernelState -import zako.zako.zako.zakoui.flash.HorizonKernelWorker import com.sukisu.ultra.ui.component.KeyEventBlocker -import com.sukisu.ultra.ui.util.* +import com.sukisu.ultra.ui.theme.CardConfig +import com.sukisu.ultra.ui.util.LocalSnackbarHost +import com.sukisu.ultra.ui.util.reboot import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import zako.zako.zako.zakoui.flash.FlashState +import zako.zako.zako.zakoui.flash.HorizonKernelState +import zako.zako.zako.zakoui.flash.HorizonKernelWorker import java.io.File import java.text.SimpleDateFormat import java.util.* -import androidx.compose.ui.input.key.Key -import androidx.compose.ui.input.key.key -import com.sukisu.ultra.ui.theme.CardConfig -import zako.zako.zako.zakoui.flash.FlashState -import kotlinx.coroutines.delay /** * @author ShirkNeko diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/screen/MoreSettings.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/screen/MoreSettings.kt index 25565cf7..3dbd4f23 100644 --- a/manager/app/src/main/java/zako/zako/zako/zakoui/screen/MoreSettings.kt +++ b/manager/app/src/main/java/zako/zako/zako/zakoui/screen/MoreSettings.kt @@ -9,89 +9,49 @@ import android.os.Build import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.* import androidx.compose.animation.core.animateFloatAsState -import androidx.compose.animation.expandVertically -import androidx.compose.animation.fadeIn -import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkVertically -import androidx.compose.animation.slideInVertically -import androidx.compose.animation.slideOutVertically -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.* import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll +import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.NavigateNext import androidx.compose.material.icons.filled.* -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Slider -import androidx.compose.material3.SliderDefaults -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberTopAppBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableFloatStateOf -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.material3.* import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp import androidx.core.content.edit import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.RootGraph +import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.sukisu.ultra.Natives import com.sukisu.ultra.R +import com.sukisu.ultra.ksuApp import com.sukisu.ultra.ui.component.ImageEditorDialog import com.sukisu.ultra.ui.component.KsuIsValid -import com.sukisu.ultra.ui.theme.CardConfig.cardElevation import com.sukisu.ultra.ui.theme.* +import com.sukisu.ultra.ui.theme.CardConfig.cardElevation import com.sukisu.ultra.ui.util.* import com.topjohnwu.superuser.Shell import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import java.util.Locale +import java.util.* import kotlin.math.roundToInt -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.text.KeyboardOptions -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material.icons.automirrored.filled.NavigateNext -import androidx.compose.material3.Card -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.IconButton -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Switch -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.vector.ImageVector -import com.sukisu.ultra.ui.theme.getCardColors -import com.sukisu.ultra.ui.theme.getCardElevation -import androidx.compose.material3.RadioButton -import androidx.compose.material3.TextButton -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.unit.sp -import com.ramcosta.composedestinations.navigation.DestinationsNavigator -import com.sukisu.ultra.ksuApp /** * @author ShirkNeko @@ -110,7 +70,7 @@ fun saveCardConfig(context: Context) { /** * 更多设置屏幕 */ -@SuppressLint("LocalContextConfigurationRead", "ObsoleteSdkInt") +@SuppressLint("LocalContextConfigurationRead", "LocalContextResourcesRead", "ObsoleteSdkInt") @OptIn(ExperimentalMaterial3Api::class) @Destination @Composable