mirror of
https://github.com/topjohnwu/Magisk.git
synced 2026-04-25 04:16:58 -04:00
Switch to Google Material 3 library
Made-with: Gemini
This commit is contained in:
@@ -46,16 +46,16 @@ dependencies {
|
||||
implementation(libs.compose.ui)
|
||||
implementation(libs.compose.ui.tooling.preview)
|
||||
debugImplementation(libs.compose.ui.tooling)
|
||||
implementation(libs.compose.material.icons.extended)
|
||||
implementation(libs.activity.compose)
|
||||
implementation(libs.lifecycle.runtime.compose)
|
||||
implementation(libs.lifecycle.viewmodel.compose)
|
||||
implementation(libs.miuix)
|
||||
implementation(libs.miuix.icons)
|
||||
implementation(libs.miuix.navigation3.ui)
|
||||
implementation(libs.compose.material3)
|
||||
|
||||
// Navigation3
|
||||
implementation(libs.navigation3.runtime)
|
||||
implementation(libs.navigationevent.compose)
|
||||
implementation(libs.lifecycle.viewmodel.navigation3)
|
||||
implementation(libs.navigation3.ui)
|
||||
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import com.topjohnwu.magisk.view.Shortcuts
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import top.yukonga.miuix.kmp.utils.MiuixPopupUtils.Companion.MiuixPopupHost
|
||||
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
class MainActivity : AppCompatActivity(), SplashScreenHost {
|
||||
@@ -162,7 +162,7 @@ class MainActivity : AppCompatActivity(), SplashScreenHost {
|
||||
onBack = { navigator.pop() },
|
||||
entryDecorators = listOf(
|
||||
rememberSaveableStateHolderNavEntryDecorator(),
|
||||
rememberViewModelStoreNavEntryDecorator()
|
||||
rememberViewModelStoreNavEntryDecorator<Any>()
|
||||
),
|
||||
entryProvider = entryProvider {
|
||||
entry<Route.Main> {
|
||||
@@ -210,7 +210,6 @@ class MainActivity : AppCompatActivity(), SplashScreenHost {
|
||||
)
|
||||
}
|
||||
MainActivityDialogs(activity = this@MainActivity)
|
||||
MiuixPopupHost()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,9 +57,9 @@ import com.topjohnwu.magisk.ui.settings.SettingsViewModel
|
||||
import com.topjohnwu.magisk.ui.superuser.SuperuserScreen
|
||||
import com.topjohnwu.magisk.ui.superuser.SuperuserViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
enum class Tab(val titleRes: Int, val iconRes: Int) {
|
||||
@@ -160,7 +160,7 @@ private fun FloatingNavigationBar(
|
||||
.padding(bottom = navBarInset + 12.dp, start = 24.dp, end = 24.dp)
|
||||
.shadow(elevation = 6.dp, shape = shape)
|
||||
.clip(shape)
|
||||
.background(MiuixTheme.colorScheme.surfaceContainer)
|
||||
.background(MaterialTheme.colorScheme.surfaceContainer)
|
||||
.fillMaxWidth()
|
||||
.height(64.dp)
|
||||
.padding(horizontal = 4.dp),
|
||||
@@ -191,9 +191,9 @@ private fun FloatingNavItem(
|
||||
) {
|
||||
val contentColor by animateColorAsState(
|
||||
targetValue = when {
|
||||
!enabled -> MiuixTheme.colorScheme.disabledOnSecondaryVariant
|
||||
selected -> MiuixTheme.colorScheme.primary
|
||||
else -> MiuixTheme.colorScheme.onSurfaceVariantActions
|
||||
!enabled -> MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f)
|
||||
selected -> MaterialTheme.colorScheme.primary
|
||||
else -> MaterialTheme.colorScheme.onSurfaceVariant
|
||||
},
|
||||
animationSpec = tween(200),
|
||||
label = "navItemColor"
|
||||
|
||||
@@ -43,12 +43,15 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withContext
|
||||
import timber.log.Timber
|
||||
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
||||
import top.yukonga.miuix.kmp.basic.InfiniteProgressIndicator
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.basic.TextButton
|
||||
import top.yukonga.miuix.kmp.extra.SuperDialog
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import java.io.IOException
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
@@ -227,29 +230,36 @@ fun rememberConfirmDialog(callback: ConfirmCallback): ConfirmDialogHandle {
|
||||
|
||||
@Composable
|
||||
private fun LoadingDialog(showDialog: MutableState<Boolean>) {
|
||||
SuperDialog(
|
||||
show = showDialog,
|
||||
onDismissRequest = {},
|
||||
content = {
|
||||
Box(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
if (showDialog.value) {
|
||||
Dialog(
|
||||
onDismissRequest = {},
|
||||
properties = DialogProperties(dismissOnBackPress = false, dismissOnClickOutside = false)
|
||||
) {
|
||||
Surface(
|
||||
shape = MaterialTheme.shapes.extraLarge,
|
||||
tonalElevation = 6.dp,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
Box(
|
||||
modifier = Modifier.padding(24.dp).fillMaxWidth(),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
InfiniteProgressIndicator(
|
||||
color = MiuixTheme.colorScheme.onBackground
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 12.dp),
|
||||
text = stringResource(com.topjohnwu.magisk.core.R.string.loading),
|
||||
)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
) {
|
||||
CircularProgressIndicator(
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
text = stringResource(com.topjohnwu.magisk.core.R.string.loading),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@@ -259,77 +269,59 @@ private fun ConfirmDialogContent(
|
||||
dismiss: () -> Unit,
|
||||
showDialog: MutableState<Boolean>
|
||||
) {
|
||||
SuperDialog(
|
||||
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top)),
|
||||
show = showDialog,
|
||||
title = visuals.title,
|
||||
onDismissRequest = {
|
||||
dismiss()
|
||||
showDialog.value = false
|
||||
},
|
||||
content = {
|
||||
Layout(
|
||||
content = {
|
||||
visuals.content?.let { content ->
|
||||
if (visuals.markdown) {
|
||||
MarkdownText(content)
|
||||
} else {
|
||||
Text(
|
||||
text = content,
|
||||
color = MiuixTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.padding(top = 12.dp)
|
||||
) {
|
||||
TextButton(
|
||||
text = visuals.dismiss
|
||||
?: stringResource(android.R.string.cancel),
|
||||
onClick = {
|
||||
dismiss()
|
||||
showDialog.value = false
|
||||
},
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Spacer(Modifier.width(20.dp))
|
||||
TextButton(
|
||||
text = visuals.confirm
|
||||
?: stringResource(android.R.string.ok),
|
||||
onClick = {
|
||||
confirm()
|
||||
showDialog.value = false
|
||||
},
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = ButtonDefaults.textButtonColorsPrimary()
|
||||
if (showDialog.value) {
|
||||
AlertDialog(
|
||||
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top)),
|
||||
onDismissRequest = {
|
||||
dismiss()
|
||||
showDialog.value = false
|
||||
},
|
||||
title = if (visuals.title.isNotEmpty()) {
|
||||
{ Text(text = visuals.title) }
|
||||
} else null,
|
||||
text = {
|
||||
visuals.content?.let { content ->
|
||||
if (visuals.markdown) {
|
||||
MarkdownText(content)
|
||||
} else {
|
||||
Text(
|
||||
text = content,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
}
|
||||
) { measurables, constraints ->
|
||||
if (measurables.size != 2) {
|
||||
val button = measurables[0].measure(constraints)
|
||||
layout(constraints.maxWidth, button.height) {
|
||||
button.place(0, 0)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
confirm()
|
||||
showDialog.value = false
|
||||
}
|
||||
} else {
|
||||
val button = measurables[1].measure(constraints)
|
||||
val content = measurables[0].measure(
|
||||
constraints.copy(maxHeight = constraints.maxHeight - button.height)
|
||||
) {
|
||||
Text(
|
||||
text = visuals.confirm ?: stringResource(android.R.string.ok)
|
||||
)
|
||||
layout(constraints.maxWidth, content.height + button.height) {
|
||||
content.place(0, 0)
|
||||
button.place(0, content.height)
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
dismiss()
|
||||
showDialog.value = false
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
text = visuals.dismiss ?: stringResource(android.R.string.cancel)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MarkdownText(text: String) {
|
||||
val contentColor = MiuixTheme.colorScheme.onBackground.toArgb()
|
||||
val contentColor = MaterialTheme.colorScheme.onBackground.toArgb()
|
||||
AndroidView(
|
||||
factory = { context ->
|
||||
TextView(context).apply {
|
||||
@@ -368,7 +360,7 @@ fun MarkdownTextAsync(getMarkdownText: suspend () -> String) {
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
InfiniteProgressIndicator(color = MiuixTheme.colorScheme.onBackground)
|
||||
CircularProgressIndicator(color = MaterialTheme.colorScheme.onBackground)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package com.topjohnwu.magisk.ui.component
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.IntRect
|
||||
import androidx.compose.ui.unit.IntSize
|
||||
import androidx.compose.ui.unit.LayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
import top.yukonga.miuix.kmp.basic.PopupPositionProvider
|
||||
|
||||
object ListPopupDefaults {
|
||||
val MenuPositionProvider = object : PopupPositionProvider {
|
||||
override fun calculatePosition(
|
||||
anchorBounds: IntRect,
|
||||
windowBounds: IntRect,
|
||||
layoutDirection: LayoutDirection,
|
||||
popupContentSize: IntSize,
|
||||
popupMargin: IntRect,
|
||||
alignment: PopupPositionProvider.Align,
|
||||
): IntOffset {
|
||||
val resolved = alignment.resolve(layoutDirection)
|
||||
val offsetX: Int
|
||||
val offsetY: Int
|
||||
when (resolved) {
|
||||
PopupPositionProvider.Align.TopStart -> {
|
||||
offsetX = anchorBounds.left + popupMargin.left
|
||||
offsetY = anchorBounds.bottom + popupMargin.top
|
||||
}
|
||||
PopupPositionProvider.Align.TopEnd -> {
|
||||
offsetX = anchorBounds.right - popupContentSize.width - popupMargin.right
|
||||
offsetY = anchorBounds.bottom + popupMargin.top
|
||||
}
|
||||
PopupPositionProvider.Align.BottomStart -> {
|
||||
offsetX = anchorBounds.left + popupMargin.left
|
||||
offsetY = anchorBounds.top - popupContentSize.height - popupMargin.bottom
|
||||
}
|
||||
PopupPositionProvider.Align.BottomEnd -> {
|
||||
offsetX = anchorBounds.right - popupContentSize.width - popupMargin.right
|
||||
offsetY = anchorBounds.top - popupContentSize.height - popupMargin.bottom
|
||||
}
|
||||
else -> {
|
||||
offsetX = if (resolved == PopupPositionProvider.Align.End) {
|
||||
anchorBounds.right - popupContentSize.width - popupMargin.right
|
||||
} else {
|
||||
anchorBounds.left + popupMargin.left
|
||||
}
|
||||
offsetY = if (windowBounds.bottom - anchorBounds.bottom > popupContentSize.height) {
|
||||
anchorBounds.bottom + popupMargin.bottom
|
||||
} else if (anchorBounds.top - windowBounds.top > popupContentSize.height) {
|
||||
anchorBounds.top - popupContentSize.height - popupMargin.top
|
||||
} else {
|
||||
anchorBounds.top + anchorBounds.height / 2 - popupContentSize.height / 2
|
||||
}
|
||||
}
|
||||
}
|
||||
return IntOffset(
|
||||
x = offsetX.coerceIn(
|
||||
windowBounds.left,
|
||||
(windowBounds.right - popupContentSize.width - popupMargin.right)
|
||||
.coerceAtLeast(windowBounds.left),
|
||||
),
|
||||
y = offsetY.coerceIn(
|
||||
(windowBounds.top + popupMargin.top)
|
||||
.coerceAtMost(windowBounds.bottom - popupContentSize.height - popupMargin.bottom),
|
||||
windowBounds.bottom - popupContentSize.height - popupMargin.bottom,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
override fun getMargins(): PaddingValues = PaddingValues(start = 20.dp)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PopupPositionProvider.Align.resolve(layoutDirection: LayoutDirection): PopupPositionProvider.Align {
|
||||
if (layoutDirection == LayoutDirection.Ltr) return this
|
||||
return when (this) {
|
||||
PopupPositionProvider.Align.Start -> PopupPositionProvider.Align.End
|
||||
PopupPositionProvider.Align.End -> PopupPositionProvider.Align.Start
|
||||
PopupPositionProvider.Align.TopStart -> PopupPositionProvider.Align.TopEnd
|
||||
PopupPositionProvider.Align.TopEnd -> PopupPositionProvider.Align.TopStart
|
||||
PopupPositionProvider.Align.BottomStart -> PopupPositionProvider.Align.BottomEnd
|
||||
PopupPositionProvider.Align.BottomEnd -> PopupPositionProvider.Align.BottomStart
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.topjohnwu.magisk.ui.component
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Switch
|
||||
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.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun SettingsArrow(
|
||||
title: String,
|
||||
summary: String? = null,
|
||||
leadingContent: @Composable (() -> Unit)? = null,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
ListItem(
|
||||
headlineContent = { Text(title) },
|
||||
supportingContent = summary?.let { { Text(it) } },
|
||||
leadingContent = leadingContent,
|
||||
trailingContent = { Icon(Icons.AutoMirrored.Filled.KeyboardArrowRight, contentDescription = null) },
|
||||
modifier = Modifier.clickable(onClick = onClick)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsSwitch(
|
||||
title: String,
|
||||
summary: String? = null,
|
||||
checked: Boolean,
|
||||
enabled: Boolean = true,
|
||||
onCheckedChange: (Boolean) -> Unit
|
||||
) {
|
||||
ListItem(
|
||||
headlineContent = { Text(title) },
|
||||
supportingContent = summary?.takeIf { it.isNotEmpty() }?.let { { Text(it) } },
|
||||
trailingContent = { Switch(checked = checked, onCheckedChange = onCheckedChange, enabled = enabled) },
|
||||
modifier = Modifier.clickable(enabled = enabled, onClick = { onCheckedChange(!checked) })
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SettingsDropdown(
|
||||
title: String,
|
||||
summary: String? = null,
|
||||
items: List<String>,
|
||||
selectedIndex: Int,
|
||||
enabled: Boolean = true,
|
||||
onSelectedIndexChange: (Int) -> Unit
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
Box {
|
||||
ListItem(
|
||||
headlineContent = { Text(title) },
|
||||
supportingContent = {
|
||||
val currentSummary = summary ?: items.getOrNull(selectedIndex) ?: ""
|
||||
if (currentSummary.isNotEmpty()) Text(currentSummary)
|
||||
},
|
||||
trailingContent = { Icon(Icons.Default.ArrowDropDown, contentDescription = null) },
|
||||
modifier = Modifier.clickable(enabled = enabled, onClick = { expanded = true })
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
items.forEachIndexed { index, item ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(item) },
|
||||
onClick = {
|
||||
onSelectedIndexChange(index)
|
||||
expanded = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SmallTitle(text: String) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
package com.topjohnwu.magisk.ui.deny
|
||||
|
||||
import com.topjohnwu.magisk.ui.util.rememberDrawablePainter
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -28,29 +28,30 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.state.ToggleableState
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.topjohnwu.magisk.ui.component.ListPopupDefaults.MenuPositionProvider
|
||||
import com.topjohnwu.magisk.ui.util.rememberDrawablePainter
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.Checkbox
|
||||
import top.yukonga.miuix.kmp.basic.CircularProgressIndicator
|
||||
import top.yukonga.miuix.kmp.basic.DropdownImpl
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.LinearProgressIndicator
|
||||
import top.yukonga.miuix.kmp.basic.ListPopupColumn
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.PopupPositionProvider
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.basic.TopAppBar
|
||||
import top.yukonga.miuix.kmp.extra.SuperListPopup
|
||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||
import top.yukonga.miuix.kmp.icon.extended.Back
|
||||
import top.yukonga.miuix.kmp.icon.extended.Sort
|
||||
import top.yukonga.miuix.kmp.icon.extended.Tune
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.automirrored.filled.Sort
|
||||
import androidx.compose.material.icons.filled.Tune
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.LinearProgressIndicator
|
||||
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.TriStateCheckbox
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DenyListScreen(viewModel: DenyListViewModel, onBack: () -> Unit) {
|
||||
val loading by viewModel.loading.collectAsState()
|
||||
@@ -64,20 +65,20 @@ fun DenyListScreen(viewModel: DenyListViewModel, onBack: () -> Unit) {
|
||||
val showSortMenu = remember { mutableStateOf(false) }
|
||||
val showFilterMenu = remember { mutableStateOf(false) }
|
||||
|
||||
val scrollBehavior = MiuixScrollBehavior()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = stringResource(CoreR.string.denylist),
|
||||
title = { Text(stringResource(CoreR.string.denylist)) },
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
onClick = onBack
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Back,
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = null,
|
||||
tint = MiuixTheme.colorScheme.onBackground
|
||||
tint = MaterialTheme.colorScheme.onBackground
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -85,50 +86,44 @@ fun DenyListScreen(viewModel: DenyListViewModel, onBack: () -> Unit) {
|
||||
Box {
|
||||
IconButton(
|
||||
onClick = { showSortMenu.value = true },
|
||||
holdDownState = showSortMenu.value,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Sort,
|
||||
imageVector = Icons.AutoMirrored.Filled.Sort,
|
||||
contentDescription = stringResource(CoreR.string.menu_sort),
|
||||
)
|
||||
}
|
||||
SuperListPopup(
|
||||
show = showSortMenu,
|
||||
popupPositionProvider = MenuPositionProvider,
|
||||
alignment = PopupPositionProvider.Align.End,
|
||||
DropdownMenu(
|
||||
expanded = showSortMenu.value,
|
||||
onDismissRequest = { showSortMenu.value = false }
|
||||
) {
|
||||
ListPopupColumn {
|
||||
val sortOptions = listOf(
|
||||
CoreR.string.sort_by_name to SortBy.NAME,
|
||||
CoreR.string.sort_by_package_name to SortBy.PACKAGE_NAME,
|
||||
CoreR.string.sort_by_install_time to SortBy.INSTALL_TIME,
|
||||
CoreR.string.sort_by_update_time to SortBy.UPDATE_TIME,
|
||||
)
|
||||
val totalSize = sortOptions.size + 1
|
||||
sortOptions.forEachIndexed { index, (resId, sort) ->
|
||||
DropdownImpl(
|
||||
text = stringResource(resId),
|
||||
optionSize = totalSize,
|
||||
isSelected = sortBy == sort,
|
||||
index = index,
|
||||
onSelectedIndexChange = {
|
||||
viewModel.setSortBy(sort)
|
||||
showSortMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
DropdownImpl(
|
||||
text = stringResource(CoreR.string.sort_reverse),
|
||||
optionSize = totalSize,
|
||||
isSelected = sortReverse,
|
||||
index = sortOptions.size,
|
||||
onSelectedIndexChange = {
|
||||
viewModel.toggleSortReverse()
|
||||
val sortOptions = listOf(
|
||||
CoreR.string.sort_by_name to SortBy.NAME,
|
||||
CoreR.string.sort_by_package_name to SortBy.PACKAGE_NAME,
|
||||
CoreR.string.sort_by_install_time to SortBy.INSTALL_TIME,
|
||||
CoreR.string.sort_by_update_time to SortBy.UPDATE_TIME,
|
||||
)
|
||||
sortOptions.forEach { (resId, sort) ->
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(resId)) },
|
||||
trailingIcon = if (sortBy == sort) {
|
||||
{ Icon(androidx.compose.material.icons.Icons.Default.Check, contentDescription = null) }
|
||||
} else null,
|
||||
onClick = {
|
||||
viewModel.setSortBy(sort)
|
||||
showSortMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(CoreR.string.sort_reverse)) },
|
||||
trailingIcon = if (sortReverse) {
|
||||
{ Icon(Icons.Default.Check, contentDescription = null) }
|
||||
} else null,
|
||||
onClick = {
|
||||
viewModel.toggleSortReverse()
|
||||
showSortMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,51 +131,45 @@ fun DenyListScreen(viewModel: DenyListViewModel, onBack: () -> Unit) {
|
||||
IconButton(
|
||||
modifier = Modifier.padding(end = 16.dp),
|
||||
onClick = { showFilterMenu.value = true },
|
||||
holdDownState = showFilterMenu.value,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Tune,
|
||||
imageVector = Icons.Default.Tune,
|
||||
contentDescription = stringResource(CoreR.string.hide_filter_hint),
|
||||
)
|
||||
}
|
||||
SuperListPopup(
|
||||
show = showFilterMenu,
|
||||
popupPositionProvider = MenuPositionProvider,
|
||||
alignment = PopupPositionProvider.Align.End,
|
||||
DropdownMenu(
|
||||
expanded = showFilterMenu.value,
|
||||
onDismissRequest = { showFilterMenu.value = false }
|
||||
) {
|
||||
ListPopupColumn {
|
||||
DropdownImpl(
|
||||
text = stringResource(CoreR.string.show_system_app),
|
||||
optionSize = 2,
|
||||
isSelected = showSystem,
|
||||
index = 0,
|
||||
onSelectedIndexChange = {
|
||||
viewModel.setShowSystem(!showSystem)
|
||||
showFilterMenu.value = false
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(CoreR.string.show_system_app)) },
|
||||
trailingIcon = if (showSystem) {
|
||||
{ Icon(Icons.Default.Check, contentDescription = null) }
|
||||
} else null,
|
||||
onClick = {
|
||||
viewModel.setShowSystem(!showSystem)
|
||||
showFilterMenu.value = false
|
||||
}
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = { Text(stringResource(CoreR.string.show_os_app)) },
|
||||
trailingIcon = if (showOS) {
|
||||
{ Icon(Icons.Default.Check, contentDescription = null) }
|
||||
} else null,
|
||||
onClick = {
|
||||
if (!showOS && !showSystem) {
|
||||
viewModel.setShowSystem(true)
|
||||
}
|
||||
)
|
||||
DropdownImpl(
|
||||
text = stringResource(CoreR.string.show_os_app),
|
||||
optionSize = 2,
|
||||
isSelected = showOS,
|
||||
index = 1,
|
||||
onSelectedIndexChange = {
|
||||
if (!showOS && !showSystem) {
|
||||
viewModel.setShowSystem(true)
|
||||
}
|
||||
viewModel.setShowOS(!showOS)
|
||||
showFilterMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
viewModel.setShowOS(!showOS)
|
||||
showFilterMenu.value = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
popupHost = { }
|
||||
}
|
||||
) { padding ->
|
||||
Column(modifier = Modifier.fillMaxSize().padding(padding)) {
|
||||
SearchInput(
|
||||
@@ -199,7 +188,7 @@ fun DenyListScreen(viewModel: DenyListViewModel, onBack: () -> Unit) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
text = stringResource(CoreR.string.loading),
|
||||
style = MiuixTheme.textStyles.headline2
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
CircularProgressIndicator()
|
||||
@@ -228,11 +217,11 @@ fun DenyListScreen(viewModel: DenyListViewModel, onBack: () -> Unit) {
|
||||
|
||||
@Composable
|
||||
private fun SearchInput(query: String, onQueryChange: (String) -> Unit, modifier: Modifier = Modifier) {
|
||||
top.yukonga.miuix.kmp.basic.TextField(
|
||||
OutlinedTextField(
|
||||
value = query,
|
||||
onValueChange = onQueryChange,
|
||||
modifier = modifier,
|
||||
label = stringResource(CoreR.string.hide_filter_hint)
|
||||
label = { Text(stringResource(CoreR.string.hide_filter_hint)) }
|
||||
)
|
||||
}
|
||||
|
||||
@@ -263,16 +252,16 @@ private fun DenyAppCard(app: DenyAppState) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = app.info.label,
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
)
|
||||
Text(
|
||||
text = app.info.packageName,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Checkbox(
|
||||
TriStateCheckbox(
|
||||
state = when {
|
||||
app.itemsChecked == 0 -> ToggleableState.Off
|
||||
app.checkedPercent < 1f -> ToggleableState.Indeterminate
|
||||
@@ -308,15 +297,15 @@ private fun ProcessRow(proc: DenyProcessState) {
|
||||
) {
|
||||
Text(
|
||||
text = proc.displayName,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = if (proc.isEnabled) MiuixTheme.colorScheme.onSurface
|
||||
else MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = if (proc.isEnabled) MaterialTheme.colorScheme.onSurface
|
||||
else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Checkbox(
|
||||
state = ToggleableState(proc.isEnabled),
|
||||
onClick = { proc.toggle() }
|
||||
checked = proc.isEnabled,
|
||||
onCheckedChange = { proc.toggle() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,17 +21,20 @@ import androidx.compose.ui.unit.sp
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.core.Const
|
||||
import com.topjohnwu.magisk.ui.terminal.TerminalScreen
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.SmallTopAppBar
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||
import top.yukonga.miuix.kmp.icon.extended.Back
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
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.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
|
||||
@Composable
|
||||
fun FlashScreen(viewModel: FlashViewModel, action: String, onBack: () -> Unit) {
|
||||
val flashState by viewModel.flashState.collectAsState()
|
||||
@@ -45,20 +48,20 @@ fun FlashScreen(viewModel: FlashViewModel, action: String, onBack: () -> Unit) {
|
||||
FlashViewModel.State.FAILED -> stringResource(CoreR.string.failure)
|
||||
}
|
||||
|
||||
val scrollBehavior = MiuixScrollBehavior()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
Scaffold(
|
||||
topBar = {
|
||||
SmallTopAppBar(
|
||||
title = "${stringResource(CoreR.string.flash_screen_title)} - $statusText",
|
||||
TopAppBar(
|
||||
title = { Text("${stringResource(CoreR.string.flash_screen_title)} - $statusText") },
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
onClick = onBack
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Back,
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = null,
|
||||
tint = MiuixTheme.colorScheme.onBackground
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -71,7 +74,7 @@ fun FlashScreen(viewModel: FlashViewModel, action: String, onBack: () -> Unit) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_save_md2),
|
||||
contentDescription = stringResource(CoreR.string.menuSaveLog),
|
||||
tint = MiuixTheme.colorScheme.onBackground
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -83,15 +86,14 @@ fun FlashScreen(viewModel: FlashViewModel, action: String, onBack: () -> Unit) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_restart),
|
||||
contentDescription = stringResource(CoreR.string.reboot),
|
||||
tint = MiuixTheme.colorScheme.onBackground
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
popupHost = { }
|
||||
}
|
||||
) { padding ->
|
||||
if (useTerminal) {
|
||||
TerminalScreen(
|
||||
@@ -124,7 +126,7 @@ fun FlashScreen(viewModel: FlashViewModel, action: String, onBack: () -> Unit) {
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
color = MiuixTheme.colorScheme.onSurface,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,21 +45,24 @@ import com.topjohnwu.magisk.core.ktx.timeDateFormat
|
||||
import com.topjohnwu.magisk.core.ktx.toTime
|
||||
import com.topjohnwu.magisk.core.model.su.SuLog
|
||||
import com.topjohnwu.magisk.ui.util.rememberDrawablePainter
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.CircularProgressIndicator
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.TabRow
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.basic.TopAppBar
|
||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||
import top.yukonga.miuix.kmp.icon.extended.Delete
|
||||
import top.yukonga.miuix.kmp.icon.extended.Download
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Download
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
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.Tab
|
||||
import androidx.compose.material3.TabRow
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun LogScreen(viewModel: LogViewModel) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
@@ -68,17 +71,17 @@ fun LogScreen(viewModel: LogViewModel) {
|
||||
stringResource(CoreR.string.superuser),
|
||||
stringResource(CoreR.string.magisk)
|
||||
)
|
||||
val scrollBehavior = MiuixScrollBehavior()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = stringResource(CoreR.string.logs),
|
||||
title = { Text(stringResource(CoreR.string.logs)) },
|
||||
actions = {
|
||||
if (selectedTab == 1) {
|
||||
IconButton(onClick = { viewModel.saveMagiskLog() }) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Download,
|
||||
imageVector = Icons.Default.Download,
|
||||
contentDescription = stringResource(CoreR.string.save_log),
|
||||
)
|
||||
}
|
||||
@@ -91,28 +94,33 @@ fun LogScreen(viewModel: LogViewModel) {
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Delete,
|
||||
imageVector = Icons.Default.Delete,
|
||||
contentDescription = stringResource(CoreR.string.clear_log),
|
||||
)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
popupHost = { }
|
||||
}
|
||||
) { padding ->
|
||||
Column(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(padding)
|
||||
) {
|
||||
TabRow(
|
||||
tabs = tabTitles,
|
||||
selectedTabIndex = selectedTab,
|
||||
onTabSelected = { selectedTab = it },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 12.dp, vertical = 8.dp)
|
||||
)
|
||||
) {
|
||||
tabTitles.forEachIndexed { index, title ->
|
||||
Tab(
|
||||
selected = selectedTab == index,
|
||||
onClick = { selectedTab = index },
|
||||
text = { Text(title) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (uiState.loading) {
|
||||
Box(
|
||||
@@ -150,8 +158,8 @@ private fun SuLogTab(logs: List<SuLog>, nestedScrollConnection: NestedScrollConn
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(CoreR.string.log_data_none),
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
@@ -220,14 +228,14 @@ private fun SuLogCard(log: SuLog) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = log.appName,
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Text(
|
||||
text = uidPidText,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
@@ -238,7 +246,7 @@ private fun SuLogCard(log: SuLog) {
|
||||
text = log.time.toTime(timeDateFormat),
|
||||
fontSize = 11.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
)
|
||||
Spacer(Modifier.height(4.dp))
|
||||
@@ -253,7 +261,7 @@ private fun SuLogCard(log: SuLog) {
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -262,8 +270,8 @@ private fun SuLogCard(log: SuLog) {
|
||||
|
||||
@Composable
|
||||
private fun SuActionBadge(allowed: Boolean) {
|
||||
val bg = if (allowed) MiuixTheme.colorScheme.primary else MiuixTheme.colorScheme.error
|
||||
val fg = if (allowed) MiuixTheme.colorScheme.onPrimary else MiuixTheme.colorScheme.onError
|
||||
val bg = if (allowed) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error
|
||||
val fg = if (allowed) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onError
|
||||
val text = if (allowed) "Approved" else "Rejected"
|
||||
Text(
|
||||
text = text,
|
||||
@@ -292,8 +300,8 @@ private fun MagiskLogTab(
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(CoreR.string.log_data_magisk_none),
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
@@ -340,7 +348,7 @@ private fun MagiskLogCard(entry: MagiskLogEntry) {
|
||||
LogLevelBadge(entry.level)
|
||||
Text(
|
||||
text = entry.tag,
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
fontWeight = FontWeight.Normal,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
@@ -351,7 +359,7 @@ private fun MagiskLogCard(entry: MagiskLogEntry) {
|
||||
text = entry.timestamp,
|
||||
fontSize = 11.sp,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
)
|
||||
}
|
||||
@@ -363,7 +371,7 @@ private fun MagiskLogCard(entry: MagiskLogEntry) {
|
||||
fontFamily = FontFamily.Monospace,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp,
|
||||
color = MiuixTheme.colorScheme.onSurface,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
maxLines = if (expanded) Int.MAX_VALUE else 3,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
|
||||
@@ -11,35 +11,37 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.topjohnwu.magisk.R
|
||||
import com.topjohnwu.magisk.ui.terminal.TerminalScreen
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.SmallTopAppBar
|
||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||
import top.yukonga.miuix.kmp.icon.extended.Back
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
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.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ActionScreen(viewModel: ActionViewModel, actionName: String, onBack: () -> Unit) {
|
||||
val actionState by viewModel.actionState.collectAsState()
|
||||
val finished = actionState != ActionViewModel.State.RUNNING
|
||||
|
||||
val scrollBehavior = MiuixScrollBehavior()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
Scaffold(
|
||||
topBar = {
|
||||
SmallTopAppBar(
|
||||
title = actionName,
|
||||
TopAppBar(
|
||||
title = { androidx.compose.material3.Text(actionName) },
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
onClick = onBack
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Back,
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = null,
|
||||
tint = MiuixTheme.colorScheme.onBackground
|
||||
tint = MaterialTheme.colorScheme.onBackground
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -52,15 +54,14 @@ fun ActionScreen(viewModel: ActionViewModel, actionName: String, onBack: () -> U
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_save_md2),
|
||||
contentDescription = stringResource(CoreR.string.menuSaveLog),
|
||||
tint = MiuixTheme.colorScheme.onBackground
|
||||
tint = MaterialTheme.colorScheme.onBackground
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
popupHost = { }
|
||||
}
|
||||
) { padding ->
|
||||
TerminalScreen(
|
||||
modifier = Modifier
|
||||
|
||||
@@ -9,6 +9,7 @@ import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -51,34 +52,36 @@ import com.topjohnwu.magisk.ui.component.ConfirmResult
|
||||
import com.topjohnwu.magisk.ui.component.MarkdownTextAsync
|
||||
import com.topjohnwu.magisk.ui.component.rememberConfirmDialog
|
||||
import kotlinx.coroutines.launch
|
||||
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.CircularProgressIndicator
|
||||
import top.yukonga.miuix.kmp.basic.FloatingActionButton
|
||||
import top.yukonga.miuix.kmp.basic.HorizontalDivider
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.Switch
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.basic.TextButton
|
||||
import top.yukonga.miuix.kmp.basic.TopAppBar
|
||||
import top.yukonga.miuix.kmp.extra.SuperDialog
|
||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||
import top.yukonga.miuix.kmp.icon.extended.Add
|
||||
import top.yukonga.miuix.kmp.icon.extended.Delete
|
||||
import top.yukonga.miuix.kmp.icon.extended.Play
|
||||
import top.yukonga.miuix.kmp.icon.extended.Undo
|
||||
import top.yukonga.miuix.kmp.icon.extended.UploadCloud
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.CloudUpload
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.filled.Undo
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FloatingActionButton
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ModuleScreen(viewModel: ModuleViewModel) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
val scrollBehavior = MiuixScrollBehavior()
|
||||
val colorScheme = MiuixTheme.colorScheme
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val activity = context as MainActivity
|
||||
@@ -134,28 +137,27 @@ fun ModuleScreen(viewModel: ModuleViewModel) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = stringResource(CoreR.string.modules),
|
||||
title = { Text(stringResource(CoreR.string.modules)) },
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = { filePicker.launch("application/zip") },
|
||||
shadowElevation = 0.dp,
|
||||
shape = CircleShape,
|
||||
modifier = Modifier
|
||||
.padding(bottom = 88.dp, end = 20.dp)
|
||||
.border(0.05.dp, colorScheme.outline.copy(alpha = 0.5f), CircleShape),
|
||||
content = {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Add,
|
||||
imageVector = Icons.Default.Add,
|
||||
contentDescription = stringResource(CoreR.string.module_action_install_external),
|
||||
modifier = Modifier.size(28.dp),
|
||||
tint = colorScheme.onPrimary
|
||||
tint = colorScheme.onPrimaryContainer
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
popupHost = { }
|
||||
}
|
||||
) { padding ->
|
||||
if (uiState.loading) {
|
||||
Box(
|
||||
@@ -178,8 +180,8 @@ fun ModuleScreen(viewModel: ModuleViewModel) {
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(CoreR.string.module_empty),
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
color = colorScheme.onSurfaceVariantSummary
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
return@Scaffold
|
||||
@@ -216,7 +218,7 @@ fun ModuleScreen(viewModel: ModuleViewModel) {
|
||||
private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateClick: (OnlineModule?) -> Unit) {
|
||||
val infoAlpha = if (!item.isRemoved && item.isEnabled && !item.showNotice) 1f else 0.5f
|
||||
val strikeThrough = if (item.isRemoved) TextDecoration.LineThrough else TextDecoration.None
|
||||
val colorScheme = MiuixTheme.colorScheme
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
val actionIconTint = colorScheme.onSurface.copy(alpha = 0.8f)
|
||||
val actionBg = colorScheme.secondaryContainer.copy(alpha = 0.8f)
|
||||
val updateBg = colorScheme.tertiaryContainer.copy(alpha = 0.6f)
|
||||
@@ -227,16 +229,15 @@ private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateCli
|
||||
val hasDescription = item.module.description.isNotBlank()
|
||||
|
||||
Card(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
insideMargin = PaddingValues(16.dp),
|
||||
onClick = { if (hasDescription) expanded = !expanded }
|
||||
modifier = Modifier.fillMaxWidth().clickable(enabled = hasDescription) { expanded = !expanded },
|
||||
) {
|
||||
Column(modifier = Modifier.alpha(infoAlpha)) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
Column(modifier = Modifier.alpha(infoAlpha)) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
@@ -244,7 +245,7 @@ private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateCli
|
||||
) {
|
||||
Text(
|
||||
text = item.module.name,
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
textDecoration = strikeThrough,
|
||||
)
|
||||
Text(
|
||||
@@ -253,8 +254,8 @@ private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateCli
|
||||
item.module.version,
|
||||
item.module.author
|
||||
),
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = colorScheme.onSurfaceVariantSummary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = colorScheme.onSurfaceVariant,
|
||||
textDecoration = strikeThrough,
|
||||
)
|
||||
}
|
||||
@@ -272,8 +273,8 @@ private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateCli
|
||||
) {
|
||||
Text(
|
||||
text = item.module.description,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = colorScheme.onSurfaceVariantSummary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = colorScheme.onSurfaceVariant,
|
||||
textDecoration = strikeThrough,
|
||||
overflow = if (expanded) TextOverflow.Clip else TextOverflow.Ellipsis,
|
||||
maxLines = if (expanded) Int.MAX_VALUE else 4,
|
||||
@@ -285,7 +286,7 @@ private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateCli
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Text(
|
||||
text = item.noticeText,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = colorScheme.primary,
|
||||
)
|
||||
}
|
||||
@@ -305,27 +306,25 @@ private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateCli
|
||||
) {
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
if (item.showAction) {
|
||||
IconButton(
|
||||
backgroundColor = actionBg,
|
||||
minHeight = 35.dp,
|
||||
minWidth = 35.dp,
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(containerColor = actionBg),
|
||||
contentPadding = PaddingValues(horizontal = 10.dp),
|
||||
onClick = { viewModel.runAction(item.module.id, item.module.name) },
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = MiuixIcons.Play,
|
||||
imageVector = Icons.Default.PlayArrow,
|
||||
tint = actionIconTint,
|
||||
contentDescription = stringResource(CoreR.string.module_action)
|
||||
)
|
||||
Text(
|
||||
text = stringResource(CoreR.string.module_action),
|
||||
color = actionIconTint,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -340,49 +339,45 @@ private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateCli
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut()
|
||||
) {
|
||||
IconButton(
|
||||
Button(
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
backgroundColor = updateBg,
|
||||
minHeight = 35.dp,
|
||||
minWidth = 35.dp,
|
||||
colors = ButtonDefaults.buttonColors(containerColor = updateBg),
|
||||
contentPadding = PaddingValues(horizontal = 10.dp),
|
||||
onClick = { onUpdateClick(item.module.updateInfo) },
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = MiuixIcons.UploadCloud,
|
||||
imageVector = Icons.Default.CloudUpload,
|
||||
tint = updateTint,
|
||||
contentDescription = stringResource(CoreR.string.update),
|
||||
)
|
||||
Text(
|
||||
text = stringResource(CoreR.string.update),
|
||||
color = updateTint,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IconButton(
|
||||
backgroundColor = if (item.isRemoved) actionBg else removeBg,
|
||||
minHeight = 35.dp,
|
||||
minWidth = 35.dp,
|
||||
Button(
|
||||
colors = ButtonDefaults.buttonColors(containerColor = if (item.isRemoved) actionBg else removeBg),
|
||||
contentPadding = PaddingValues(horizontal = 10.dp),
|
||||
onClick = { viewModel.toggleRemove(item) },
|
||||
enabled = !item.isUpdated
|
||||
) {
|
||||
val tint = if (item.isRemoved) actionIconTint else removeTint
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = if (item.isRemoved) MiuixIcons.Undo else MiuixIcons.Delete,
|
||||
imageVector = if (item.isRemoved) Icons.Default.Undo else Icons.Default.Delete,
|
||||
tint = tint,
|
||||
contentDescription = null
|
||||
)
|
||||
@@ -392,10 +387,11 @@ private fun ModuleCard(item: ModuleItem, viewModel: ModuleViewModel, onUpdateCli
|
||||
else CoreR.string.module_state_remove
|
||||
),
|
||||
color = tint,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -413,36 +409,34 @@ private fun OnlineModuleDialog(
|
||||
item.name, item.version, item.versionCode
|
||||
)
|
||||
|
||||
SuperDialog(
|
||||
show = showDialog,
|
||||
title = title,
|
||||
onDismissRequest = onDismiss,
|
||||
) {
|
||||
MarkdownTextAsync {
|
||||
val str = svc.fetchString(item.changelog)
|
||||
if (str.length > 1000) str.substring(0, 1000) else str
|
||||
}
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.End,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
TextButton(
|
||||
text = stringResource(android.R.string.cancel),
|
||||
onClick = onDismiss,
|
||||
)
|
||||
Spacer(Modifier.weight(1f))
|
||||
TextButton(
|
||||
text = stringResource(CoreR.string.download),
|
||||
onClick = { onDownload(false) },
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
TextButton(
|
||||
text = stringResource(CoreR.string.install),
|
||||
onClick = { onDownload(true) },
|
||||
colors = ButtonDefaults.textButtonColorsPrimary()
|
||||
)
|
||||
}
|
||||
if (showDialog.value) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(title) },
|
||||
text = {
|
||||
MarkdownTextAsync {
|
||||
val str = svc.fetchString(item.changelog)
|
||||
if (str.length > 1000) str.substring(0, 1000) else str
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = { onDownload(true) }
|
||||
) {
|
||||
Text(stringResource(CoreR.string.install))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
Row {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(android.R.string.cancel))
|
||||
}
|
||||
Spacer(Modifier.weight(1f))
|
||||
TextButton(onClick = { onDownload(false) }) {
|
||||
Text(stringResource(CoreR.string.download))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,32 +36,34 @@ import com.topjohnwu.magisk.core.tasks.AppMigration
|
||||
import com.topjohnwu.magisk.core.utils.LocaleSetting
|
||||
import com.topjohnwu.magisk.core.utils.MediaStoreUtils
|
||||
import com.topjohnwu.magisk.ui.theme.ThemeState
|
||||
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.SmallTitle
|
||||
import top.yukonga.miuix.kmp.basic.TextButton
|
||||
import top.yukonga.miuix.kmp.basic.TextField
|
||||
import top.yukonga.miuix.kmp.basic.TopAppBar
|
||||
import top.yukonga.miuix.kmp.extra.SuperArrow
|
||||
import top.yukonga.miuix.kmp.extra.SuperDialog
|
||||
import top.yukonga.miuix.kmp.extra.SuperDropdown
|
||||
import top.yukonga.miuix.kmp.extra.SuperSwitch
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import com.topjohnwu.magisk.ui.component.SettingsArrow
|
||||
import com.topjohnwu.magisk.ui.component.SettingsDropdown
|
||||
import com.topjohnwu.magisk.ui.component.SettingsSwitch
|
||||
import com.topjohnwu.magisk.ui.component.SmallTitle
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SettingsScreen(viewModel: SettingsViewModel) {
|
||||
val scrollBehavior = MiuixScrollBehavior()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = stringResource(CoreR.string.settings),
|
||||
title = { Text(stringResource(CoreR.string.settings)) },
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
popupHost = { }
|
||||
}
|
||||
) { padding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -98,7 +100,7 @@ private fun CustomizationSection(viewModel: SettingsViewModel) {
|
||||
if (LocaleSetting.useLocaleManager) {
|
||||
val locale = LocaleSetting.instance.appLocale
|
||||
val summary = locale?.getDisplayName(locale) ?: stringResource(CoreR.string.system_default)
|
||||
SuperArrow(
|
||||
SettingsArrow(
|
||||
title = stringResource(CoreR.string.language),
|
||||
summary = summary,
|
||||
onClick = {
|
||||
@@ -111,7 +113,7 @@ private fun CustomizationSection(viewModel: SettingsViewModel) {
|
||||
var selectedIndex by remember {
|
||||
mutableIntStateOf(tags.indexOf(Config.locale).coerceAtLeast(0))
|
||||
}
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.language),
|
||||
items = names.toList(),
|
||||
selectedIndex = selectedIndex,
|
||||
@@ -128,7 +130,7 @@ private fun CustomizationSection(viewModel: SettingsViewModel) {
|
||||
resources.getStringArray(CoreR.array.color_mode).toList()
|
||||
}
|
||||
var colorMode by remember { mutableIntStateOf(Config.colorMode) }
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.settings_color_mode),
|
||||
items = colorModeEntries,
|
||||
selectedIndex = colorMode,
|
||||
@@ -140,7 +142,7 @@ private fun CustomizationSection(viewModel: SettingsViewModel) {
|
||||
)
|
||||
|
||||
if (isRunningAsStub && ShortcutManagerCompat.isRequestPinShortcutSupported(context)) {
|
||||
SuperArrow(
|
||||
SettingsArrow(
|
||||
title = stringResource(CoreR.string.add_shortcut_title),
|
||||
summary = stringResource(CoreR.string.setting_add_shortcut_summary),
|
||||
onClick = { viewModel.requestAddShortcut() }
|
||||
@@ -168,7 +170,7 @@ private fun AppSettingsSection(viewModel: SettingsViewModel) {
|
||||
}
|
||||
var showUrlDialog by remember { mutableStateOf(false) }
|
||||
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.settings_update_channel_title),
|
||||
items = updateChannelEntries,
|
||||
selectedIndex = updateChannel,
|
||||
@@ -188,7 +190,7 @@ private fun AppSettingsSection(viewModel: SettingsViewModel) {
|
||||
show = showUrlDialog,
|
||||
onDismiss = { showUrlDialog = false }
|
||||
)
|
||||
SuperArrow(
|
||||
SettingsArrow(
|
||||
title = stringResource(CoreR.string.settings_update_custom),
|
||||
summary = Config.customChannelUrl.ifBlank { null },
|
||||
onClick = { showUrlDialog = true }
|
||||
@@ -197,7 +199,7 @@ private fun AppSettingsSection(viewModel: SettingsViewModel) {
|
||||
|
||||
// DoH Toggle
|
||||
var doh by remember { mutableStateOf(Config.doh) }
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.settings_doh_title),
|
||||
summary = stringResource(CoreR.string.settings_doh_description),
|
||||
checked = doh,
|
||||
@@ -209,7 +211,7 @@ private fun AppSettingsSection(viewModel: SettingsViewModel) {
|
||||
|
||||
// Update Checker
|
||||
var checkUpdate by remember { mutableStateOf(Config.checkUpdate) }
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.settings_check_update_title),
|
||||
summary = stringResource(CoreR.string.settings_check_update_summary),
|
||||
checked = checkUpdate,
|
||||
@@ -225,7 +227,7 @@ private fun AppSettingsSection(viewModel: SettingsViewModel) {
|
||||
show = showDownloadDialog,
|
||||
onDismiss = { showDownloadDialog = false }
|
||||
)
|
||||
SuperArrow(
|
||||
SettingsArrow(
|
||||
title = stringResource(CoreR.string.settings_download_path_title),
|
||||
summary = MediaStoreUtils.fullPath(Config.downloadDir),
|
||||
onClick = {
|
||||
@@ -235,7 +237,7 @@ private fun AppSettingsSection(viewModel: SettingsViewModel) {
|
||||
|
||||
// Random Package Name
|
||||
var randName by remember { mutableStateOf(Config.randName) }
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.settings_random_name_title),
|
||||
summary = stringResource(CoreR.string.settings_random_name_description),
|
||||
checked = randName,
|
||||
@@ -255,7 +257,7 @@ private fun MagiskSection(viewModel: SettingsViewModel) {
|
||||
SmallTitle(text = stringResource(CoreR.string.magisk))
|
||||
Card(modifier = Modifier.fillMaxWidth()) {
|
||||
// Systemless Hosts
|
||||
SuperArrow(
|
||||
SettingsArrow(
|
||||
title = stringResource(CoreR.string.settings_hosts_title),
|
||||
summary = stringResource(CoreR.string.settings_hosts_summary),
|
||||
onClick = { viewModel.createHosts() }
|
||||
@@ -264,7 +266,7 @@ private fun MagiskSection(viewModel: SettingsViewModel) {
|
||||
if (Const.Version.atLeast_24_0()) {
|
||||
// Zygisk
|
||||
var zygisk by remember { mutableStateOf(Config.zygisk) }
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.zygisk),
|
||||
summary = stringResource(
|
||||
if (zygisk != Info.isZygiskEnabled) CoreR.string.reboot_apply_change
|
||||
@@ -280,7 +282,7 @@ private fun MagiskSection(viewModel: SettingsViewModel) {
|
||||
|
||||
// DenyList
|
||||
val denyListEnabled by viewModel.denyListEnabled.collectAsState()
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.settings_denylist_title),
|
||||
summary = stringResource(CoreR.string.settings_denylist_summary),
|
||||
checked = denyListEnabled,
|
||||
@@ -288,7 +290,7 @@ private fun MagiskSection(viewModel: SettingsViewModel) {
|
||||
)
|
||||
|
||||
// DenyList Config
|
||||
SuperArrow(
|
||||
SettingsArrow(
|
||||
title = stringResource(CoreR.string.settings_denylist_config_title),
|
||||
summary = stringResource(CoreR.string.settings_denylist_config_summary),
|
||||
onClick = { viewModel.navigateToDenyList() }
|
||||
@@ -309,7 +311,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
// Tapjack (SDK < S)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
var tapjack by remember { mutableStateOf(Config.suTapjack) }
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.settings_su_tapjack_title),
|
||||
summary = stringResource(CoreR.string.settings_su_tapjack_summary),
|
||||
checked = tapjack,
|
||||
@@ -322,7 +324,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
|
||||
// Authentication
|
||||
var suAuth by remember { mutableStateOf(Config.suAuth) }
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.settings_su_auth_title),
|
||||
summary = stringResource(
|
||||
if (Info.isDeviceSecure) CoreR.string.settings_su_auth_summary
|
||||
@@ -343,7 +345,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
resources.getStringArray(CoreR.array.su_access).toList()
|
||||
}
|
||||
var accessMode by remember { mutableIntStateOf(Config.rootMode) }
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.superuser_access),
|
||||
items = accessEntries,
|
||||
selectedIndex = accessMode,
|
||||
@@ -361,7 +363,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
resources.getStringArray(CoreR.array.multiuser_summary).toList()
|
||||
}
|
||||
var multiuserMode by remember { mutableIntStateOf(Config.suMultiuserMode) }
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.multiuser_mode),
|
||||
summary = multiuserDescriptions.getOrElse(multiuserMode) { "" },
|
||||
items = multiuserEntries,
|
||||
@@ -381,7 +383,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
resources.getStringArray(CoreR.array.namespace_summary).toList()
|
||||
}
|
||||
var mntNamespaceMode by remember { mutableIntStateOf(Config.suMntNamespaceMode) }
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.mount_namespace_mode),
|
||||
summary = namespaceDescriptions.getOrElse(mntNamespaceMode) { "" },
|
||||
items = namespaceEntries,
|
||||
@@ -397,7 +399,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
resources.getStringArray(CoreR.array.auto_response).toList()
|
||||
}
|
||||
var autoResponse by remember { mutableIntStateOf(Config.suAutoResponse) }
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.auto_response),
|
||||
items = autoResponseEntries,
|
||||
selectedIndex = autoResponse,
|
||||
@@ -418,7 +420,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
var timeoutIndex by remember {
|
||||
mutableIntStateOf(timeoutValues.indexOf(Config.suDefaultTimeout).coerceAtLeast(0))
|
||||
}
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.request_timeout),
|
||||
items = timeoutEntries,
|
||||
selectedIndex = timeoutIndex,
|
||||
@@ -433,7 +435,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
resources.getStringArray(CoreR.array.su_notification).toList()
|
||||
}
|
||||
var suNotification by remember { mutableIntStateOf(Config.suNotification) }
|
||||
SuperDropdown(
|
||||
SettingsDropdown(
|
||||
title = stringResource(CoreR.string.superuser_notification),
|
||||
items = notifEntries,
|
||||
selectedIndex = suNotification,
|
||||
@@ -446,7 +448,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
// Reauthenticate (SDK < O)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
var reAuth by remember { mutableStateOf(Config.suReAuth) }
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.settings_su_reauth_title),
|
||||
summary = stringResource(CoreR.string.settings_su_reauth_summary),
|
||||
checked = reAuth,
|
||||
@@ -460,7 +462,7 @@ private fun SuperuserSection(viewModel: SettingsViewModel) {
|
||||
// Restrict (version >= 30.1)
|
||||
if (Const.Version.atLeast_30_1()) {
|
||||
var restrict by remember { mutableStateOf(Config.suRestrict) }
|
||||
SuperSwitch(
|
||||
SettingsSwitch(
|
||||
title = stringResource(CoreR.string.settings_su_restrict_title),
|
||||
summary = stringResource(CoreR.string.settings_su_restrict_summary),
|
||||
checked = restrict,
|
||||
@@ -481,29 +483,29 @@ private fun UpdateChannelUrlDialog(show: Boolean, onDismiss: () -> Unit) {
|
||||
showState.value = show
|
||||
var url by rememberSaveable { mutableStateOf(Config.customChannelUrl) }
|
||||
|
||||
SuperDialog(
|
||||
show = showState,
|
||||
onDismissRequest = onDismiss,
|
||||
insideMargin = DpSize(24.dp, 24.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(top = 8.dp)) {
|
||||
TextField(
|
||||
value = url,
|
||||
onValueChange = { url = it },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = stringResource(CoreR.string.settings_update_custom_msg)
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
TextButton(
|
||||
text = stringResource(android.R.string.ok),
|
||||
onClick = {
|
||||
Config.customChannelUrl = url
|
||||
Info.resetUpdate()
|
||||
onDismiss()
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
if (showState.value) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(CoreR.string.settings_update_custom_msg)) },
|
||||
text = {
|
||||
OutlinedTextField(
|
||||
value = url,
|
||||
onValueChange = { url = it },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
Config.customChannelUrl = url
|
||||
Info.resetUpdate()
|
||||
onDismiss()
|
||||
}
|
||||
) {
|
||||
Text(stringResource(android.R.string.ok))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,32 +515,34 @@ private fun DownloadPathDialog(show: Boolean, onDismiss: () -> Unit) {
|
||||
showState.value = show
|
||||
var path by rememberSaveable { mutableStateOf(Config.downloadDir) }
|
||||
|
||||
SuperDialog(
|
||||
show = showState,
|
||||
onDismissRequest = onDismiss,
|
||||
insideMargin = DpSize(24.dp, 24.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(top = 8.dp)) {
|
||||
top.yukonga.miuix.kmp.basic.Text(
|
||||
text = stringResource(CoreR.string.settings_download_path_message, MediaStoreUtils.fullPath(path)),
|
||||
modifier = Modifier.padding(bottom = 8.dp)
|
||||
)
|
||||
TextField(
|
||||
value = path,
|
||||
onValueChange = { path = it },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = stringResource(CoreR.string.settings_download_path_title)
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
TextButton(
|
||||
text = stringResource(android.R.string.ok),
|
||||
onClick = {
|
||||
Config.downloadDir = path
|
||||
onDismiss()
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
if (showState.value) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(CoreR.string.settings_download_path_title)) },
|
||||
text = {
|
||||
Column {
|
||||
Text(
|
||||
text = stringResource(CoreR.string.settings_download_path_message, MediaStoreUtils.fullPath(path)),
|
||||
modifier = Modifier.padding(bottom = 8.dp)
|
||||
)
|
||||
OutlinedTextField(
|
||||
value = path,
|
||||
onValueChange = { path = it },
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
Config.downloadDir = path
|
||||
onDismiss()
|
||||
}
|
||||
) {
|
||||
Text(stringResource(android.R.string.ok))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,37 +553,31 @@ private fun HideAppDialog(show: Boolean, onDismiss: () -> Unit, onConfirm: (Stri
|
||||
var appName by rememberSaveable { mutableStateOf("Settings") }
|
||||
val isError = appName.length > AppMigration.MAX_LABEL_LENGTH || appName.isBlank()
|
||||
|
||||
SuperDialog(
|
||||
show = showState,
|
||||
title = stringResource(CoreR.string.settings_hide_app_title),
|
||||
onDismissRequest = onDismiss,
|
||||
insideMargin = DpSize(24.dp, 24.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(top = 8.dp)) {
|
||||
TextField(
|
||||
value = appName,
|
||||
onValueChange = { appName = it },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = stringResource(CoreR.string.settings_app_name_hint),
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
TextButton(
|
||||
text = stringResource(android.R.string.cancel),
|
||||
onClick = onDismiss,
|
||||
modifier = Modifier.weight(1f)
|
||||
if (showState.value) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(CoreR.string.settings_hide_app_title)) },
|
||||
text = {
|
||||
OutlinedTextField(
|
||||
value = appName,
|
||||
onValueChange = { appName = it },
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
label = { Text(stringResource(CoreR.string.settings_app_name_hint)) }
|
||||
)
|
||||
Spacer(Modifier.width(20.dp))
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
text = stringResource(android.R.string.ok),
|
||||
onClick = { if (!isError) onConfirm(appName) },
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = ButtonDefaults.textButtonColorsPrimary()
|
||||
)
|
||||
onClick = { if (!isError) onConfirm(appName) }
|
||||
) {
|
||||
Text(stringResource(android.R.string.ok))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(android.R.string.cancel))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,34 +586,26 @@ private fun RestoreDialog(show: Boolean, onDismiss: () -> Unit, onConfirm: () ->
|
||||
val showState = rememberSaveable { mutableStateOf(show) }
|
||||
showState.value = show
|
||||
|
||||
SuperDialog(
|
||||
show = showState,
|
||||
title = stringResource(CoreR.string.settings_restore_app_title),
|
||||
onDismissRequest = onDismiss,
|
||||
insideMargin = DpSize(24.dp, 24.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(top = 8.dp)) {
|
||||
top.yukonga.miuix.kmp.basic.Text(
|
||||
text = stringResource(CoreR.string.restore_app_confirmation),
|
||||
color = MiuixTheme.colorScheme.onSurface,
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
TextButton(
|
||||
text = stringResource(android.R.string.cancel),
|
||||
onClick = onDismiss,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Spacer(Modifier.width(20.dp))
|
||||
TextButton(
|
||||
text = stringResource(android.R.string.ok),
|
||||
onClick = onConfirm,
|
||||
modifier = Modifier.weight(1f),
|
||||
colors = ButtonDefaults.textButtonColorsPrimary()
|
||||
if (showState.value) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(stringResource(CoreR.string.settings_restore_app_title)) },
|
||||
text = {
|
||||
Text(
|
||||
text = stringResource(CoreR.string.restore_app_confirmation),
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = onConfirm) {
|
||||
Text(stringResource(android.R.string.ok))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(android.R.string.cancel))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,19 +28,21 @@ import com.topjohnwu.magisk.ui.component.ConfirmResult
|
||||
import com.topjohnwu.magisk.ui.component.rememberConfirmDialog
|
||||
import com.topjohnwu.magisk.ui.util.rememberDrawablePainter
|
||||
import kotlinx.coroutines.launch
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.Icon
|
||||
import top.yukonga.miuix.kmp.basic.IconButton
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.Switch
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.basic.TopAppBar
|
||||
import top.yukonga.miuix.kmp.icon.MiuixIcons
|
||||
import top.yukonga.miuix.kmp.icon.extended.Back
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.Card
|
||||
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.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SuperuserDetailScreen(
|
||||
uid: Int,
|
||||
@@ -50,7 +52,7 @@ fun SuperuserDetailScreen(
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
val items = uiState.policies.filter { it.policy.uid == uid }
|
||||
val item = items.firstOrNull()
|
||||
val scrollBehavior = MiuixScrollBehavior()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val scope = rememberCoroutineScope()
|
||||
val revokeDialog = rememberConfirmDialog()
|
||||
val revokeTitle = stringResource(CoreR.string.su_revoke_title)
|
||||
@@ -61,22 +63,21 @@ fun SuperuserDetailScreen(
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = stringResource(CoreR.string.superuser_setting),
|
||||
title = { Text(stringResource(CoreR.string.superuser_setting)) },
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
onClick = onBack
|
||||
) {
|
||||
Icon(
|
||||
imageVector = MiuixIcons.Back,
|
||||
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||
contentDescription = stringResource(CoreR.string.back),
|
||||
)
|
||||
}
|
||||
},
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
popupHost = { }
|
||||
}
|
||||
) { padding ->
|
||||
if (item == null) return@Scaffold
|
||||
|
||||
@@ -109,7 +110,7 @@ fun SuperuserDetailScreen(
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = item.title,
|
||||
style = MiuixTheme.textStyles.headline2,
|
||||
style = MaterialTheme.typography.headlineMedium,
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
)
|
||||
if (item.isSharedUid) {
|
||||
@@ -119,13 +120,13 @@ fun SuperuserDetailScreen(
|
||||
}
|
||||
Text(
|
||||
text = item.packageName,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
Text(
|
||||
text = "UID: ${item.policy.uid}",
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -197,7 +198,7 @@ private fun SwitchRow(
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Spacer(Modifier.width(16.dp))
|
||||
@@ -212,8 +213,8 @@ private fun SwitchRow(
|
||||
private fun RevokeRow() {
|
||||
Text(
|
||||
text = stringResource(CoreR.string.superuser_toggle_revoke),
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
color = MiuixTheme.colorScheme.error,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.error,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 16.dp)
|
||||
|
||||
@@ -33,30 +33,31 @@ import androidx.compose.ui.unit.sp
|
||||
import com.topjohnwu.magisk.ui.navigation.LocalNavigator
|
||||
import com.topjohnwu.magisk.ui.navigation.Route
|
||||
import com.topjohnwu.magisk.ui.util.rememberDrawablePainter
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.CircularProgressIndicator
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
import top.yukonga.miuix.kmp.basic.Scaffold
|
||||
import top.yukonga.miuix.kmp.basic.Switch
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.basic.TopAppBar
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SuperuserScreen(viewModel: SuperuserViewModel) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
val scrollBehavior = MiuixScrollBehavior()
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||
val navigator = LocalNavigator.current
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = stringResource(CoreR.string.superuser),
|
||||
title = { Text(stringResource(CoreR.string.superuser)) },
|
||||
scrollBehavior = scrollBehavior
|
||||
)
|
||||
},
|
||||
popupHost = { }
|
||||
}
|
||||
) { padding ->
|
||||
if (uiState.loading) {
|
||||
Box(
|
||||
@@ -79,8 +80,8 @@ fun SuperuserScreen(viewModel: SuperuserViewModel) {
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(CoreR.string.superuser_policy_none),
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
return@Scaffold
|
||||
@@ -142,7 +143,7 @@ private fun PolicyCard(
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = item.title,
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier = Modifier.weight(1f, fill = false),
|
||||
)
|
||||
if (item.isSharedUid) {
|
||||
@@ -152,8 +153,8 @@ private fun PolicyCard(
|
||||
}
|
||||
Text(
|
||||
text = item.packageName,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -163,7 +164,7 @@ private fun PolicyCard(
|
||||
.fillMaxHeight()
|
||||
.padding(vertical = 12.dp)
|
||||
.width(0.5.dp)
|
||||
.background(MiuixTheme.colorScheme.dividerLine)
|
||||
.background(MaterialTheme.colorScheme.outlineVariant)
|
||||
)
|
||||
|
||||
Box(
|
||||
@@ -185,11 +186,11 @@ private fun PolicyCard(
|
||||
internal fun SharedUidBadge(modifier: Modifier = Modifier) {
|
||||
Text(
|
||||
text = "SharedUID",
|
||||
color = MiuixTheme.colorScheme.onPrimary,
|
||||
color = MaterialTheme.colorScheme.onPrimary,
|
||||
fontSize = 10.sp,
|
||||
maxLines = 1,
|
||||
modifier = modifier
|
||||
.background(MiuixTheme.colorScheme.primary, RoundedCornerShape(6.dp))
|
||||
.background(MaterialTheme.colorScheme.primary, RoundedCornerShape(6.dp))
|
||||
.padding(horizontal = 6.dp, vertical = 2.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import com.topjohnwu.magisk.ui.theme.Theme
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import top.yukonga.miuix.kmp.utils.MiuixPopupUtils.Companion.MiuixPopupHost
|
||||
|
||||
open class SuRequestActivity : AppCompatActivity(), UntrackedActivity {
|
||||
|
||||
@@ -92,7 +91,6 @@ open class SuRequestActivity : AppCompatActivity(), UntrackedActivity {
|
||||
MagiskTheme {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
SuRequestScreen(viewModel = viewModel)
|
||||
MiuixPopupHost()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,13 +34,12 @@ import androidx.compose.ui.unit.dp
|
||||
import com.topjohnwu.magisk.core.ktx.toast
|
||||
import com.topjohnwu.magisk.ui.superuser.SharedUidBadge
|
||||
import com.topjohnwu.magisk.ui.util.rememberDrawablePainter
|
||||
import top.yukonga.miuix.kmp.basic.ButtonDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Card
|
||||
import top.yukonga.miuix.kmp.basic.Slider
|
||||
import top.yukonga.miuix.kmp.basic.SliderDefaults
|
||||
import top.yukonga.miuix.kmp.basic.Text
|
||||
import top.yukonga.miuix.kmp.basic.TextButton
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedButton
|
||||
import androidx.compose.material3.Slider
|
||||
import androidx.compose.material3.Text
|
||||
import com.topjohnwu.magisk.core.R as CoreR
|
||||
|
||||
@OptIn(ExperimentalComposeUiApi::class)
|
||||
@@ -103,7 +102,7 @@ fun SuRequestScreen(viewModel: SuRequestViewModel) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MiuixTheme.textStyles.body1,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
@@ -116,8 +115,8 @@ fun SuRequestScreen(viewModel: SuRequestViewModel) {
|
||||
}
|
||||
Text(
|
||||
text = packageName,
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
@@ -128,8 +127,8 @@ fun SuRequestScreen(viewModel: SuRequestViewModel) {
|
||||
|
||||
Text(
|
||||
text = stringResource(CoreR.string.su_request_title),
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = MiuixTheme.colorScheme.primary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
fontWeight = FontWeight.Bold,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
@@ -138,8 +137,8 @@ fun SuRequestScreen(viewModel: SuRequestViewModel) {
|
||||
|
||||
Text(
|
||||
text = "Permission timeout: $sliderLabel",
|
||||
style = MiuixTheme.textStyles.body2,
|
||||
color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.fillMaxWidth().padding(start = 8.dp),
|
||||
)
|
||||
Spacer(Modifier.height(8.dp))
|
||||
@@ -152,9 +151,6 @@ fun SuRequestScreen(viewModel: SuRequestViewModel) {
|
||||
},
|
||||
valueRange = 0f..5f,
|
||||
steps = 4,
|
||||
showKeyPoints = true,
|
||||
height = 20.dp,
|
||||
hapticEffect = SliderDefaults.SliderHapticEffect.Step,
|
||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 4.dp)
|
||||
)
|
||||
Spacer(Modifier.height(16.dp))
|
||||
@@ -163,22 +159,15 @@ fun SuRequestScreen(viewModel: SuRequestViewModel) {
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
TextButton(
|
||||
text = denyText,
|
||||
OutlinedButton(
|
||||
onClick = { viewModel.denyPressed() },
|
||||
modifier = Modifier.weight(1f),
|
||||
cornerRadius = 12.dp,
|
||||
minHeight = 40.dp,
|
||||
insideMargin = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
|
||||
)
|
||||
TextButton(
|
||||
text = stringResource(CoreR.string.grant),
|
||||
) {
|
||||
Text(denyText)
|
||||
}
|
||||
Button(
|
||||
enabled = grantEnabled,
|
||||
colors = ButtonDefaults.textButtonColorsPrimary(),
|
||||
onClick = { viewModel.grantPressed() },
|
||||
cornerRadius = 12.dp,
|
||||
minHeight = 40.dp,
|
||||
insideMargin = PaddingValues(horizontal = 16.dp, vertical = 8.dp),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.then(
|
||||
@@ -200,7 +189,9 @@ fun SuRequestScreen(viewModel: SuRequestViewModel) {
|
||||
}
|
||||
} else Modifier
|
||||
)
|
||||
)
|
||||
) {
|
||||
Text(stringResource(CoreR.string.grant))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
package com.topjohnwu.magisk.ui.theme
|
||||
|
||||
import android.os.Build
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
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.CompositionLocalProvider
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.topjohnwu.magisk.core.Config
|
||||
import top.yukonga.miuix.kmp.theme.ColorSchemeMode
|
||||
import top.yukonga.miuix.kmp.theme.LocalContentColor
|
||||
import top.yukonga.miuix.kmp.theme.MiuixTheme
|
||||
import top.yukonga.miuix.kmp.theme.ThemeController
|
||||
|
||||
object ThemeState {
|
||||
var colorMode by mutableIntStateOf(Config.colorMode)
|
||||
@@ -22,18 +24,28 @@ fun MagiskTheme(
|
||||
) {
|
||||
val isDark = isSystemInDarkTheme()
|
||||
val mode = ThemeState.colorMode
|
||||
val controller = when (mode) {
|
||||
1 -> ThemeController(ColorSchemeMode.Light)
|
||||
2 -> ThemeController(ColorSchemeMode.Dark)
|
||||
3 -> ThemeController(ColorSchemeMode.MonetSystem, isDark = isDark)
|
||||
4 -> ThemeController(ColorSchemeMode.MonetLight)
|
||||
5 -> ThemeController(ColorSchemeMode.MonetDark)
|
||||
else -> ThemeController(ColorSchemeMode.System)
|
||||
val context = LocalContext.current
|
||||
|
||||
val isDarkTheme = when (mode) {
|
||||
1 -> false
|
||||
2 -> true
|
||||
3 -> isDark
|
||||
4 -> false
|
||||
5 -> true
|
||||
else -> isDark
|
||||
}
|
||||
MiuixTheme(controller = controller) {
|
||||
CompositionLocalProvider(
|
||||
LocalContentColor provides MiuixTheme.colorScheme.onBackground,
|
||||
content = content
|
||||
)
|
||||
|
||||
val useDynamicColor = mode in listOf(3, 4, 5) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
||||
|
||||
val colorScheme = when {
|
||||
useDynamicColor && isDarkTheme -> dynamicDarkColorScheme(context)
|
||||
useDynamicColor && !isDarkTheme -> dynamicLightColorScheme(context)
|
||||
isDarkTheme -> darkColorScheme()
|
||||
else -> lightColorScheme()
|
||||
}
|
||||
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
||||
@@ -66,6 +66,8 @@ rikka-insets = { module = "dev.rikka.rikkax.insets:insets", version.ref = "rikka
|
||||
activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activity-compose" }
|
||||
compose-bom = { module = "androidx.compose:compose-bom", version.ref = "compose-bom" }
|
||||
compose-ui = { module = "androidx.compose.ui:ui" }
|
||||
compose-material3 = { module = "androidx.compose.material3:material3" }
|
||||
compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" }
|
||||
compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" }
|
||||
compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview" }
|
||||
lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle" }
|
||||
@@ -74,6 +76,7 @@ miuix = { module = "top.yukonga.miuix.kmp:miuix-android", version.ref = "miuix"
|
||||
miuix-icons = { module = "top.yukonga.miuix.kmp:miuix-icons-android", version.ref = "miuix" }
|
||||
miuix-navigation3-ui = { module = "top.yukonga.miuix.kmp:miuix-navigation3-ui-android", version.ref = "miuix" }
|
||||
navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "navigation3" }
|
||||
navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "navigation3" }
|
||||
navigationevent-compose = { module = "androidx.navigationevent:navigationevent-compose", version.ref = "navigationevent" }
|
||||
lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycle" }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user