mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2025-07-11 06:32:34 +08:00
Compare commits
2 Commits
compose-de
...
feat/toolt
Author | SHA1 | Date | |
---|---|---|---|
1510aa58f2 | |||
111c74329f |
@ -34,7 +34,7 @@ sealed class PatchBundleSource(initialName: String, val uid: Int, directory: Fil
|
||||
|
||||
private val _nameFlow = MutableStateFlow(initialName)
|
||||
val nameFlow =
|
||||
_nameFlow.map { it.ifEmpty { app.getString(if (isDefault) R.string.patches_name_default else R.string.patches_name_fallback) } }
|
||||
_nameFlow.map { it.ifEmpty { app.getString(if (isDefault) R.string.bundle_name_default else R.string.bundle_name_fallback) } }
|
||||
|
||||
suspend fun getName() = nameFlow.first()
|
||||
|
||||
|
@ -50,7 +50,7 @@ sealed class RemotePatchBundle(name: String, id: Int, directory: File, val endpo
|
||||
suspend fun setAutoUpdate(value: Boolean) = configRepository.setAutoUpdate(uid, value)
|
||||
|
||||
companion object {
|
||||
const val updateFailMsg = "Failed to update patches"
|
||||
const val updateFailMsg = "Failed to update patch bundle(s)"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ class PatchBundleRepository(
|
||||
getBundlesByType<RemotePatchBundle>().forEach { it.downloadLatest() }
|
||||
|
||||
suspend fun updateCheck() =
|
||||
uiSafe(app, R.string.patches_download_fail, "Failed to update bundles") {
|
||||
uiSafe(app, R.string.source_download_fail, "Failed to update bundles") {
|
||||
coroutineScope {
|
||||
if (!networkInfo.isSafe()) {
|
||||
Log.d(tag, "Skipping update check because the network is down or metered.")
|
||||
|
@ -69,10 +69,15 @@ fun AppTopBar(
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = {
|
||||
if (onBackClick != null) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.back),
|
||||
) {
|
||||
IconButton(onClick = onBackClick) {
|
||||
backIcon()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actions = actions,
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
@ -108,10 +113,15 @@ fun AppTopBar(
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = {
|
||||
if (onBackClick != null) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.back),
|
||||
) {
|
||||
IconButton(onClick = onBackClick) {
|
||||
backIcon()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actions = actions,
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
|
@ -27,6 +27,10 @@ fun ArrowButton(
|
||||
)
|
||||
|
||||
onClick?.let {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(description),
|
||||
) {
|
||||
IconButton(onClick = it) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.KeyboardArrowUp,
|
||||
@ -36,6 +40,7 @@ fun ArrowButton(
|
||||
.then(modifier)
|
||||
)
|
||||
}
|
||||
}
|
||||
} ?: Icon(
|
||||
imageVector = Icons.Filled.KeyboardArrowUp,
|
||||
contentDescription = stringResource(description),
|
||||
|
@ -30,7 +30,7 @@ fun ExceptionViewerDialog(text: String, onDismiss: () -> Unit) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
BundleTopBar(
|
||||
title = stringResource(R.string.patches_error),
|
||||
title = stringResource(R.string.bundle_error),
|
||||
onBackClick = onDismiss,
|
||||
backIcon = {
|
||||
Icon(
|
||||
@ -39,6 +39,10 @@ fun ExceptionViewerDialog(text: String, onDismiss: () -> Unit) {
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.share),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
val sendIntent: Intent = Intent().apply {
|
||||
@ -60,6 +64,7 @@ fun ExceptionViewerDialog(text: String, onDismiss: () -> Unit) {
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
|
@ -138,6 +138,10 @@ fun NotificationCard(
|
||||
)
|
||||
}
|
||||
if (onDismiss != null) {
|
||||
TooltipWrap(
|
||||
modifier = modifier,
|
||||
tooltip = stringResource(R.string.close),
|
||||
) {
|
||||
IconButton(onClick = onDismiss) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.Close,
|
||||
@ -149,6 +153,7 @@ fun NotificationCard(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NotificationCardInstance(
|
||||
|
@ -33,6 +33,10 @@ fun PasswordField(modifier: Modifier = Modifier, value: String, onValueChange: (
|
||||
label = label,
|
||||
modifier = modifier,
|
||||
trailingIcon = {
|
||||
TooltipWrap(
|
||||
modifier = modifier,
|
||||
tooltip = if (visible) stringResource(R.string.show_password_field) else stringResource(R.string.hide_password_field),
|
||||
) {
|
||||
IconButton(onClick = {
|
||||
visible = !visible
|
||||
}) {
|
||||
@ -41,6 +45,7 @@ fun PasswordField(modifier: Modifier = Modifier, value: String, onValueChange: (
|
||||
}
|
||||
Icon(icon, stringResource(description))
|
||||
}
|
||||
}
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Password
|
||||
|
@ -48,6 +48,10 @@ fun SearchView(
|
||||
onExpandedChange = onActiveChange,
|
||||
placeholder = placeholder,
|
||||
leadingIcon = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.back),
|
||||
) {
|
||||
IconButton(onClick = { onActiveChange(false) }) {
|
||||
Icon(
|
||||
Icons.AutoMirrored.Filled.ArrowBack,
|
||||
@ -55,6 +59,7 @@ fun SearchView(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
expanded = true,
|
||||
|
@ -0,0 +1,94 @@
|
||||
package app.revanced.manager.ui.component
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.PlainTooltip
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TooltipBox
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.window.PopupPositionProvider
|
||||
|
||||
/**
|
||||
* Wraps a composable with a tooltip.
|
||||
*
|
||||
* @param modifier the [Modifier] to be applied to the [TooltipBox]
|
||||
* @param tooltip the text to be displayed in the [TooltipBox]
|
||||
* @param positionProvider Anchor point for the tooltip, defaults to [TooltipDefaults.rememberPlainTooltipPositionProvider]
|
||||
* @param content The composable UI to be wrapped with [TooltipBox]
|
||||
*
|
||||
* @see [TooltipBox]
|
||||
*/
|
||||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
fun TooltipWrap(
|
||||
modifier: Modifier,
|
||||
tooltip: String,
|
||||
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val tooltipState = rememberTooltipState()
|
||||
val haptic = LocalHapticFeedback.current
|
||||
|
||||
LaunchedEffect(tooltipState.isVisible) {
|
||||
if (tooltipState.isVisible) {
|
||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
}
|
||||
}
|
||||
|
||||
TooltipBox(
|
||||
modifier = modifier,
|
||||
positionProvider = positionProvider,
|
||||
tooltip = {
|
||||
PlainTooltip { Text(tooltip) }
|
||||
},
|
||||
state = tooltipState
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a composable with a tooltip.
|
||||
*
|
||||
* @param modifier the [Modifier] to be applied to the [TooltipBox]
|
||||
* @param tooltip the R.string to be displayed in the [TooltipBox]
|
||||
* @param positionProvider Anchor point for the tooltip, defaults to [TooltipDefaults.rememberPlainTooltipPositionProvider]
|
||||
* @param content The composable UI to be wrapped with [TooltipBox]
|
||||
*
|
||||
* @see [TooltipBox]
|
||||
*/
|
||||
@Composable
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
fun TooltipWrap(
|
||||
modifier: Modifier,
|
||||
@StringRes tooltip: Int,
|
||||
positionProvider: PopupPositionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(),
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
val tooltipState = rememberTooltipState()
|
||||
val haptic = LocalHapticFeedback.current
|
||||
|
||||
LaunchedEffect(tooltipState.isVisible) {
|
||||
if (tooltipState.isVisible) {
|
||||
haptic.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||
}
|
||||
}
|
||||
|
||||
TooltipBox(
|
||||
modifier = modifier,
|
||||
positionProvider = positionProvider,
|
||||
tooltip = {
|
||||
PlainTooltip { Text(stringResource(tooltip)) }
|
||||
},
|
||||
state = tooltipState
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
@ -92,8 +92,8 @@ fun BaseBundleDialog(
|
||||
|
||||
if (remoteUrl != null) {
|
||||
BundleListItem(
|
||||
headlineText = stringResource(R.string.auto_update),
|
||||
supportingText = stringResource(R.string.auto_update_description),
|
||||
headlineText = stringResource(R.string.bundle_auto_update),
|
||||
supportingText = stringResource(R.string.bundle_auto_update_description),
|
||||
trailingContent = {
|
||||
HapticSwitch(
|
||||
checked = autoUpdate,
|
||||
@ -113,7 +113,7 @@ fun BaseBundleDialog(
|
||||
if (showUrlInputDialog) {
|
||||
TextInputDialog(
|
||||
initial = url,
|
||||
title = stringResource(R.string.patches_url),
|
||||
title = stringResource(R.string.bundle_input_source_url),
|
||||
onDismissRequest = { showUrlInputDialog = false },
|
||||
onConfirm = {
|
||||
showUrlInputDialog = false
|
||||
@ -134,7 +134,7 @@ fun BaseBundleDialog(
|
||||
showUrlInputDialog = true
|
||||
}
|
||||
),
|
||||
headlineText = stringResource(R.string.patches_url),
|
||||
headlineText = stringResource(R.string.bundle_input_source_url),
|
||||
supportingText = url.ifEmpty {
|
||||
stringResource(R.string.field_not_set)
|
||||
}
|
||||
@ -143,8 +143,8 @@ fun BaseBundleDialog(
|
||||
|
||||
val patchesClickable = patchCount > 0
|
||||
BundleListItem(
|
||||
headlineText = stringResource(R.string.patches),
|
||||
supportingText = stringResource(R.string.view_patches),
|
||||
headlineText = stringResource(R.string.bundle_view_patches),
|
||||
supportingText = stringResource(R.string.bundle_view_all_patches, patchCount),
|
||||
modifier = Modifier.clickable(
|
||||
enabled = patchesClickable,
|
||||
onClick = onPatchesClick
|
||||
|
@ -22,6 +22,7 @@ import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.isDefaul
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.nameState
|
||||
import app.revanced.manager.ui.component.ExceptionViewerDialog
|
||||
import app.revanced.manager.ui.component.FullscreenDialog
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.compose.koinInject
|
||||
|
||||
@ -73,6 +74,10 @@ fun BundleInformationDialog(
|
||||
},
|
||||
actions = {
|
||||
if (!bundle.isDefault) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.delete),
|
||||
) {
|
||||
IconButton(onClick = onDeleteRequest) {
|
||||
Icon(
|
||||
Icons.Outlined.DeleteOutline,
|
||||
@ -80,7 +85,12 @@ fun BundleInformationDialog(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isLocal && hasNetwork) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.refresh),
|
||||
) {
|
||||
IconButton(onClick = onUpdate) {
|
||||
Icon(
|
||||
Icons.Outlined.Update,
|
||||
@ -89,6 +99,7 @@ fun BundleInformationDialog(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
@ -119,8 +130,8 @@ fun BundleInformationDialog(
|
||||
)
|
||||
|
||||
BundleListItem(
|
||||
headlineText = stringResource(R.string.patches_error),
|
||||
supportingText = stringResource(R.string.patches_error_description),
|
||||
headlineText = stringResource(R.string.bundle_error),
|
||||
supportingText = stringResource(R.string.bundle_error_description),
|
||||
trailingContent = {
|
||||
Icon(
|
||||
Icons.AutoMirrored.Outlined.ArrowRight,
|
||||
@ -133,8 +144,8 @@ fun BundleInformationDialog(
|
||||
|
||||
if (state is PatchBundleSource.State.Missing && !isLocal) {
|
||||
BundleListItem(
|
||||
headlineText = stringResource(R.string.patches_error),
|
||||
supportingText = stringResource(R.string.patches_not_downloaded),
|
||||
headlineText = stringResource(R.string.bundle_error),
|
||||
supportingText = stringResource(R.string.bundle_not_downloaded),
|
||||
modifier = Modifier.clickable(onClick = onUpdate)
|
||||
)
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ fun BundleItem(
|
||||
onDelete()
|
||||
viewBundleDialogPage = false
|
||||
},
|
||||
title = stringResource(R.string.delete),
|
||||
description = stringResource(R.string.patches_delete_single_dialog_description, name),
|
||||
title = stringResource(R.string.bundle_delete_single_dialog_title),
|
||||
description = stringResource(R.string.bundle_delete_single_dialog_description, name),
|
||||
icon = Icons.Outlined.Delete
|
||||
)
|
||||
}
|
||||
@ -100,8 +100,8 @@ fun BundleItem(
|
||||
Row {
|
||||
val icon = remember(state) {
|
||||
when (state) {
|
||||
is PatchBundleSource.State.Failed -> Icons.Outlined.ErrorOutline to R.string.patches_error
|
||||
is PatchBundleSource.State.Missing -> Icons.Outlined.Warning to R.string.patches_missing
|
||||
is PatchBundleSource.State.Failed -> Icons.Outlined.ErrorOutline to R.string.bundle_error
|
||||
is PatchBundleSource.State.Missing -> Icons.Outlined.Warning to R.string.bundle_missing
|
||||
is PatchBundleSource.State.Loaded -> null
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ fun BundlePatchesDialog(
|
||||
Scaffold(
|
||||
topBar = {
|
||||
BundleTopBar(
|
||||
title = stringResource(R.string.patches),
|
||||
title = stringResource(R.string.bundle_patches),
|
||||
onBackClick = onDismissRequest,
|
||||
backIcon = {
|
||||
Icon(
|
||||
@ -133,10 +133,10 @@ fun PatchItem(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
PatchInfoChip(
|
||||
text = "$PACKAGE_ICON ${stringResource(R.string.patches_view_any_package)}"
|
||||
text = "$PACKAGE_ICON ${stringResource(R.string.bundle_view_patches_any_package)}"
|
||||
)
|
||||
PatchInfoChip(
|
||||
text = "$VERSION_ICON ${stringResource(R.string.patches_view_any_version)}"
|
||||
text = "$VERSION_ICON ${stringResource(R.string.bundle_view_patches_any_version)}"
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
@ -13,14 +13,14 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource
|
||||
import app.revanced.manager.domain.bundles.PatchBundleSource.Extensions.nameState
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -50,7 +50,7 @@ fun BundleSelector(bundles: List<PatchBundleSource>, onFinish: (PatchBundleSourc
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(R.string.select),
|
||||
text = "Select bundle",
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
|
@ -10,7 +10,11 @@ import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -33,10 +37,15 @@ fun BundleTopBar(
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = {
|
||||
if (onBackClick != null) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.back),
|
||||
) {
|
||||
IconButton(onClick = onBackClick) {
|
||||
backIcon()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actions = actions,
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
|
@ -77,7 +77,7 @@ fun ImportPatchBundleDialog(
|
||||
AlertDialogExtended(
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(stringResource(if (currentStep == 0) R.string.select else R.string.add_patches))
|
||||
Text(stringResource(if (currentStep == 0) R.string.select else R.string.add_patch_bundle))
|
||||
},
|
||||
text = {
|
||||
steps[currentStep]()
|
||||
@ -126,7 +126,7 @@ fun SelectBundleTypeStep(
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
text = stringResource(R.string.select_patches_type_dialog_description)
|
||||
text = stringResource(R.string.select_bundle_type_dialog_description)
|
||||
)
|
||||
Column {
|
||||
ListItem(
|
||||
@ -136,7 +136,7 @@ fun SelectBundleTypeStep(
|
||||
),
|
||||
headlineContent = { Text(stringResource(R.string.enter_url)) },
|
||||
overlineContent = { Text(stringResource(R.string.recommended)) },
|
||||
supportingContent = { Text(stringResource(R.string.remote_patches_description)) },
|
||||
supportingContent = { Text(stringResource(R.string.remote_bundle_description)) },
|
||||
leadingContent = {
|
||||
HapticRadioButton(
|
||||
selected = bundleType == BundleType.Remote,
|
||||
@ -152,7 +152,7 @@ fun SelectBundleTypeStep(
|
||||
onClick = { onBundleTypeSelected(BundleType.Local) }
|
||||
),
|
||||
headlineContent = { Text(stringResource(R.string.select_from_storage)) },
|
||||
supportingContent = { Text(stringResource(R.string.local_patches_description)) },
|
||||
supportingContent = { Text(stringResource(R.string.local_bundle_description)) },
|
||||
overlineContent = { },
|
||||
leadingContent = {
|
||||
HapticRadioButton(
|
||||
@ -185,10 +185,11 @@ fun ImportBundleStep(
|
||||
) {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(stringResource(R.string.patches))
|
||||
Text(stringResource(R.string.patch_bundle_field))
|
||||
},
|
||||
supportingContent = { Text(stringResource(if (patchBundle != null) R.string.file_field_set else R.string.file_field_not_set)) },
|
||||
trailingContent = {
|
||||
// TODO: Determine if this button should be [TooltipWrap]'ped
|
||||
IconButton(onClick = launchPatchActivity) {
|
||||
Icon(imageVector = Icons.Default.Topic, contentDescription = null)
|
||||
}
|
||||
@ -206,7 +207,7 @@ fun ImportBundleStep(
|
||||
OutlinedTextField(
|
||||
value = remoteUrl,
|
||||
onValueChange = onRemoteUrlChange,
|
||||
label = { Text(stringResource(R.string.patches_url)) }
|
||||
label = { Text(stringResource(R.string.bundle_url)) }
|
||||
)
|
||||
}
|
||||
Column(
|
||||
|
@ -65,6 +65,7 @@ import app.revanced.manager.ui.component.FloatInputDialog
|
||||
import app.revanced.manager.ui.component.FullscreenDialog
|
||||
import app.revanced.manager.ui.component.IntInputDialog
|
||||
import app.revanced.manager.ui.component.LongInputDialog
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
|
||||
import app.revanced.manager.ui.component.haptics.HapticRadioButton
|
||||
import app.revanced.manager.ui.component.haptics.HapticSwitch
|
||||
@ -74,13 +75,11 @@ import app.revanced.manager.util.saver.snapshotStateListSaver
|
||||
import app.revanced.manager.util.saver.snapshotStateSetSaver
|
||||
import app.revanced.manager.util.toast
|
||||
import app.revanced.manager.util.transparentListItemColors
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.koin.compose.koinInject
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
import sh.calvin.reorderable.ReorderableItem
|
||||
import sh.calvin.reorderable.rememberReorderableLazyColumnState
|
||||
import sh.calvin.reorderable.rememberReorderableLazyListState
|
||||
import java.io.Serializable
|
||||
import kotlin.random.Random
|
||||
@ -113,10 +112,15 @@ private interface OptionEditor<T : Any> {
|
||||
|
||||
@Composable
|
||||
fun ListItemTrailingContent(scope: OptionEditorScope<T>) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.edit),
|
||||
) {
|
||||
IconButton(onClick = { clickAction(scope) }) {
|
||||
Icon(Icons.Outlined.Edit, stringResource(R.string.edit))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Dialog(scope: OptionEditorScope<T>)
|
||||
@ -249,6 +253,10 @@ private object StringOptionEditor : OptionEditor<String> {
|
||||
},
|
||||
trailingIcon = {
|
||||
var showDropdownMenu by rememberSaveable { mutableStateOf(false) }
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.string_option_menu_description),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { showDropdownMenu = true }
|
||||
) {
|
||||
@ -257,6 +265,7 @@ private object StringOptionEditor : OptionEditor<String> {
|
||||
stringResource(R.string.string_option_menu_description)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
DropdownMenu(
|
||||
expanded = showDropdownMenu,
|
||||
@ -551,6 +560,10 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
|
||||
},
|
||||
actions = {
|
||||
if (deleteMode) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.select_deselect_all),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (items.size == deletionTargets.size) deletionTargets.clear()
|
||||
@ -562,6 +575,11 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
|
||||
stringResource(R.string.select_deselect_all)
|
||||
)
|
||||
}
|
||||
}
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.delete),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
items.removeIf { it.key in deletionTargets }
|
||||
@ -574,12 +592,18 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
|
||||
stringResource(R.string.delete)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.reset),
|
||||
) {
|
||||
IconButton(onClick = items::clear) {
|
||||
Icon(Icons.Outlined.Restore, stringResource(R.string.reset))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
floatingActionButton = {
|
||||
@ -643,6 +667,10 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
|
||||
),
|
||||
tonalElevation = if (deleteMode && item.key in deletionTargets) 8.dp else 0.dp,
|
||||
leadingContent = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.drag_handle),
|
||||
) {
|
||||
IconButton(
|
||||
modifier = Modifier.draggableHandle(interactionSource = interactionSource),
|
||||
onClick = {},
|
||||
@ -652,6 +680,7 @@ private class ListOptionEditor<T : Serializable>(private val elementEditor: Opti
|
||||
stringResource(R.string.drag_handle)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
headlineContent = {
|
||||
if (item.value == null) return@ListItem Text(
|
||||
|
@ -17,6 +17,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.domain.manager.base.Preference
|
||||
import app.revanced.manager.ui.component.IntInputDialog
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@ -65,6 +66,10 @@ fun IntegerItem(
|
||||
headlineContent = stringResource(headline),
|
||||
supportingContent = stringResource(description),
|
||||
trailingContent = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.edit),
|
||||
) {
|
||||
IconButton(onClick = { dialogOpen = true }) {
|
||||
Icon(
|
||||
Icons.Outlined.Edit,
|
||||
@ -72,5 +77,6 @@ fun IntegerItem(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -44,6 +44,7 @@ import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.LoadingIndicator
|
||||
import app.revanced.manager.ui.component.NonSuggestedVersionDialog
|
||||
import app.revanced.manager.ui.component.SearchView
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import app.revanced.manager.ui.model.SelectedApp
|
||||
import app.revanced.manager.ui.viewmodel.AppSelectorViewModel
|
||||
import app.revanced.manager.util.APK_MIMETYPE
|
||||
@ -162,10 +163,15 @@ fun AppSelectorScreen(
|
||||
scrollBehavior = scrollBehavior,
|
||||
onBackClick = onBackClick,
|
||||
actions = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.search_patches),
|
||||
) {
|
||||
IconButton(onClick = { search = true }) {
|
||||
Icon(Icons.Outlined.Search, stringResource(R.string.search))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
|
@ -62,8 +62,9 @@ import app.revanced.manager.ui.component.AlertDialogExtended
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.AutoUpdatesDialog
|
||||
import app.revanced.manager.ui.component.AvailableUpdateDialog
|
||||
import app.revanced.manager.ui.component.NotificationCard
|
||||
import app.revanced.manager.ui.component.ConfirmDialog
|
||||
import app.revanced.manager.ui.component.NotificationCard
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import app.revanced.manager.ui.component.bundle.BundleTopBar
|
||||
import app.revanced.manager.ui.component.bundle.ImportPatchBundleDialog
|
||||
import app.revanced.manager.ui.component.haptics.HapticFloatingActionButton
|
||||
@ -79,7 +80,7 @@ enum class DashboardPage(
|
||||
val icon: ImageVector
|
||||
) {
|
||||
DASHBOARD(R.string.tab_apps, Icons.Outlined.Apps),
|
||||
BUNDLES(R.string.tab_patches, Icons.Outlined.Source),
|
||||
BUNDLES(R.string.tab_bundles, Icons.Outlined.Source),
|
||||
}
|
||||
|
||||
@SuppressLint("BatteryLife")
|
||||
@ -93,7 +94,7 @@ fun DashboardScreen(
|
||||
onDownloaderPluginClick: () -> Unit,
|
||||
onAppClick: (String) -> Unit
|
||||
) {
|
||||
val bundlesSelectable by remember { derivedStateOf { vm.selectedSources.isNotEmpty() } }
|
||||
val bundlesSelectable by remember { derivedStateOf { vm.selectedSources.size > 0 } }
|
||||
val availablePatches by vm.availablePatches.collectAsStateWithLifecycle(0)
|
||||
val showNewDownloaderPluginsNotification by vm.newDownloaderPluginsAvailable.collectAsStateWithLifecycle(
|
||||
false
|
||||
@ -164,8 +165,8 @@ fun DashboardScreen(
|
||||
vm.selectedSources.forEach { if (!it.isDefault) vm.delete(it) }
|
||||
vm.cancelSourceSelection()
|
||||
},
|
||||
title = stringResource(R.string.delete),
|
||||
description = stringResource(R.string.patches_delete_multiple_dialog_description),
|
||||
title = stringResource(R.string.bundle_delete_multiple_dialog_title),
|
||||
description = stringResource(R.string.bundle_delete_multiple_dialog_description),
|
||||
icon = Icons.Outlined.Delete
|
||||
)
|
||||
}
|
||||
@ -174,7 +175,7 @@ fun DashboardScreen(
|
||||
topBar = {
|
||||
if (bundlesSelectable) {
|
||||
BundleTopBar(
|
||||
title = stringResource(R.string.patches_selected, vm.selectedSources.size),
|
||||
title = stringResource(R.string.bundles_selected, vm.selectedSources.size),
|
||||
onBackClick = vm::cancelSourceSelection,
|
||||
backIcon = {
|
||||
Icon(
|
||||
@ -183,6 +184,10 @@ fun DashboardScreen(
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.delete),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
showDeleteConfirmationDialog = true
|
||||
@ -193,6 +198,11 @@ fun DashboardScreen(
|
||||
stringResource(R.string.delete)
|
||||
)
|
||||
}
|
||||
}
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.refresh),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
vm.selectedSources.forEach { vm.update(it) }
|
||||
@ -205,12 +215,17 @@ fun DashboardScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
} else {
|
||||
AppTopBar(
|
||||
title = stringResource(R.string.app_name),
|
||||
actions = {
|
||||
if (!vm.updatedManagerVersion.isNullOrEmpty()) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.update),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onUpdateClick,
|
||||
) {
|
||||
@ -223,15 +238,25 @@ fun DashboardScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.settings),
|
||||
) {
|
||||
IconButton(onClick = onSettingsClick) {
|
||||
Icon(Icons.Outlined.Settings, stringResource(R.string.settings))
|
||||
}
|
||||
}
|
||||
},
|
||||
applyContainerColor = true
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.add),
|
||||
) {
|
||||
HapticFloatingActionButton(
|
||||
onClick = {
|
||||
vm.cancelSourceSelection()
|
||||
@ -239,7 +264,7 @@ fun DashboardScreen(
|
||||
when (pagerState.currentPage) {
|
||||
DashboardPage.DASHBOARD.ordinal -> {
|
||||
if (availablePatches < 1) {
|
||||
androidContext.toast(androidContext.getString(R.string.no_patch_found))
|
||||
androidContext.toast(androidContext.getString(R.string.patches_unavailable))
|
||||
composableScope.launch {
|
||||
pagerState.animateScrollToPage(
|
||||
DashboardPage.BUNDLES.ordinal
|
||||
@ -262,6 +287,7 @@ fun DashboardScreen(
|
||||
}
|
||||
) { Icon(Icons.Default.Add, stringResource(R.string.add)) }
|
||||
}
|
||||
}
|
||||
) { paddingValues ->
|
||||
Column(Modifier.padding(paddingValues)) {
|
||||
TabRow(
|
||||
|
@ -48,6 +48,7 @@ import app.revanced.manager.ui.component.AppScaffold
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.ConfirmDialog
|
||||
import app.revanced.manager.ui.component.InstallerStatusDialog
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
|
||||
import app.revanced.manager.ui.component.patcher.InstallPickerDialog
|
||||
import app.revanced.manager.ui.component.patcher.Steps
|
||||
@ -164,18 +165,28 @@ fun PatcherScreen(
|
||||
bottomBar = {
|
||||
BottomAppBar(
|
||||
actions = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.save_apk),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { exportApkLauncher.launch("${viewModel.packageName}_${viewModel.version}_revanced_patched.apk") },
|
||||
enabled = patcherSucceeded == true
|
||||
) {
|
||||
Icon(Icons.Outlined.Save, stringResource(id = R.string.save_apk))
|
||||
}
|
||||
}
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.save_logs),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { viewModel.exportLogs(context) },
|
||||
enabled = patcherSucceeded != null
|
||||
) {
|
||||
Icon(Icons.Outlined.PostAdd, stringResource(id = R.string.save_logs))
|
||||
}
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
AnimatedVisibility(visible = canInstall) {
|
||||
|
@ -69,6 +69,7 @@ import app.revanced.manager.ui.component.FullscreenDialog
|
||||
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.SafeguardDialog
|
||||
import app.revanced.manager.ui.component.SearchBar
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import app.revanced.manager.ui.component.haptics.HapticCheckbox
|
||||
import app.revanced.manager.ui.component.haptics.HapticExtendedFloatingActionButton
|
||||
import app.revanced.manager.ui.component.haptics.HapticTab
|
||||
@ -259,6 +260,10 @@ fun PatchesSelectorScreen(
|
||||
animationSpec = tween(durationMillis = 400, easing = EaseInOut),
|
||||
label = "SearchBar back button"
|
||||
)
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.back),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (searchExpanded) {
|
||||
@ -274,6 +279,7 @@ fun PatchesSelectorScreen(
|
||||
contentDescription = stringResource(R.string.back)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
trailingIcon = {
|
||||
AnimatedContent(
|
||||
@ -282,6 +288,10 @@ fun PatchesSelectorScreen(
|
||||
transitionSpec = { fadeIn() togetherWith fadeOut() }
|
||||
) { searchExpanded ->
|
||||
if (searchExpanded) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.clear),
|
||||
) {
|
||||
IconButton(
|
||||
onClick = { setQuery("") },
|
||||
enabled = query.isNotEmpty()
|
||||
@ -291,7 +301,12 @@ fun PatchesSelectorScreen(
|
||||
contentDescription = stringResource(R.string.clear)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.more),
|
||||
) {
|
||||
IconButton(onClick = { showBottomSheet = true }) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.FilterList,
|
||||
@ -301,6 +316,7 @@ fun PatchesSelectorScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
val bundle = bundles[pagerState.currentPage]
|
||||
|
||||
@ -353,6 +369,10 @@ fun PatchesSelectorScreen(
|
||||
Column(
|
||||
horizontalAlignment = Alignment.End,
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.reset),
|
||||
) {
|
||||
SmallFloatingActionButton(
|
||||
onClick = viewModel::reset,
|
||||
@ -360,6 +380,7 @@ fun PatchesSelectorScreen(
|
||||
) {
|
||||
Icon(Icons.Outlined.Restore, stringResource(R.string.reset))
|
||||
}
|
||||
}
|
||||
HapticExtendedFloatingActionButton(
|
||||
text = {
|
||||
Text(
|
||||
@ -517,6 +538,7 @@ private fun PatchItem(
|
||||
supportingContent = patch.description?.let { { Text(it) } },
|
||||
trailingContent = {
|
||||
if (patch.options?.isNotEmpty() == true) {
|
||||
// TODO: Determine if this button should be [TooltipWrap]
|
||||
IconButton(onClick = onOptionsDialog, enabled = compatible) {
|
||||
Icon(Icons.Outlined.Settings, null)
|
||||
}
|
||||
@ -540,6 +562,10 @@ fun ListHeader(
|
||||
},
|
||||
trailingContent = onHelpClick?.let {
|
||||
{
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.help),
|
||||
) {
|
||||
IconButton(onClick = it) {
|
||||
Icon(
|
||||
Icons.AutoMirrored.Outlined.HelpOutline,
|
||||
@ -547,6 +573,7 @@ fun ListHeader(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
colors = transparentListItemColors
|
||||
)
|
||||
@ -619,10 +646,15 @@ private fun OptionsDialog(
|
||||
title = patch.name,
|
||||
onBackClick = onDismissRequest,
|
||||
actions = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.reset),
|
||||
) {
|
||||
IconButton(onClick = reset) {
|
||||
Icon(Icons.Outlined.Restore, stringResource(R.string.reset))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
|
@ -49,6 +49,7 @@ import app.revanced.manager.R
|
||||
import app.revanced.manager.network.dto.ReVancedSocial
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
||||
import app.revanced.manager.ui.model.navigation.Settings
|
||||
import app.revanced.manager.ui.viewmodel.AboutViewModel
|
||||
@ -252,6 +253,10 @@ fun AboutSettingsScreen(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
|
||||
) {
|
||||
socialButtons.forEach { (icon, text, onClick) ->
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = text,
|
||||
) {
|
||||
IconButton(
|
||||
onClick = onClick,
|
||||
modifier = Modifier.padding(end = 8.dp),
|
||||
@ -265,6 +270,7 @@ fun AboutSettingsScreen(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OutlinedCard(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant)
|
||||
|
@ -48,6 +48,7 @@ import app.revanced.manager.R
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.GroupHeader
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import app.revanced.manager.ui.component.settings.BooleanItem
|
||||
import app.revanced.manager.ui.component.settings.IntegerItem
|
||||
import app.revanced.manager.ui.component.settings.SafeguardBooleanItem
|
||||
@ -243,10 +244,15 @@ private fun APIUrlDialog(currentUrl: String, defaultUrl: String, onSubmit: (Stri
|
||||
onValueChange = { url = it },
|
||||
label = { Text(stringResource(R.string.api_url)) },
|
||||
trailingIcon = {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.api_url_dialog_reset),
|
||||
) {
|
||||
IconButton(onClick = { url = defaultUrl }) {
|
||||
Icon(Icons.Outlined.Restore, stringResource(R.string.api_url_dialog_reset))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -48,13 +48,13 @@ fun DeveloperSettingsScreen(
|
||||
description = R.string.developer_options_description,
|
||||
)
|
||||
|
||||
GroupHeader(stringResource(R.string.patches))
|
||||
GroupHeader(stringResource(R.string.patch_bundles_section))
|
||||
SettingsListItem(
|
||||
headlineContent = stringResource(R.string.patches_force_download),
|
||||
headlineContent = stringResource(R.string.patch_bundles_force_download),
|
||||
modifier = Modifier.clickable(onClick = vm::redownloadBundles)
|
||||
)
|
||||
SettingsListItem(
|
||||
headlineContent = stringResource(R.string.patches_reset),
|
||||
headlineContent = stringResource(R.string.patch_bundles_reset),
|
||||
modifier = Modifier.clickable(onClick = vm::redownloadBundles)
|
||||
)
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ import app.revanced.manager.ui.component.ExceptionViewerDialog
|
||||
import app.revanced.manager.ui.component.GroupHeader
|
||||
import app.revanced.manager.ui.component.LazyColumnWithScrollbar
|
||||
import app.revanced.manager.ui.component.ConfirmDialog
|
||||
import app.revanced.manager.ui.component.TooltipWrap
|
||||
import app.revanced.manager.ui.component.haptics.HapticCheckbox
|
||||
import app.revanced.manager.ui.component.settings.SettingsListItem
|
||||
import app.revanced.manager.ui.viewmodel.DownloadsViewModel
|
||||
@ -81,11 +82,16 @@ fun DownloadsSettingsScreen(
|
||||
onBackClick = onBackClick,
|
||||
actions = {
|
||||
if (viewModel.appSelection.isNotEmpty()) {
|
||||
TooltipWrap(
|
||||
modifier = Modifier,
|
||||
tooltip = stringResource(R.string.delete),
|
||||
) {
|
||||
IconButton(onClick = { showDeleteConfirmationDialog = true }) {
|
||||
Icon(Icons.Default.Delete, stringResource(R.string.delete))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
|
@ -240,8 +240,8 @@ fun ImportExportSettingsScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
headline = R.string.patch_selection_reset_patches,
|
||||
description = R.string.patch_selection_reset_patches_description
|
||||
headline = R.string.patch_selection_reset_bundle,
|
||||
description = R.string.patch_selection_reset_bundle_description
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -296,8 +296,8 @@ fun ImportExportSettingsScreen(
|
||||
}
|
||||
}
|
||||
},
|
||||
headline = R.string.patch_options_reset,
|
||||
description = R.string.patch_options_reset_all,
|
||||
headline = R.string.patch_options_reset_bundle,
|
||||
description = R.string.patch_options_reset_bundle_description,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -135,13 +135,13 @@ class DashboardViewModel(
|
||||
|
||||
uiSafe(
|
||||
app,
|
||||
R.string.patches_download_fail,
|
||||
R.string.source_download_fail,
|
||||
RemotePatchBundle.updateFailMsg
|
||||
) {
|
||||
if (bundle.update())
|
||||
app.toast(app.getString(R.string.patches_update_success, bundle.getName()))
|
||||
app.toast(app.getString(R.string.bundle_update_success, bundle.getName()))
|
||||
else
|
||||
app.toast(app.getString(R.string.patches_update_unavailable, bundle.getName()))
|
||||
app.toast(app.getString(R.string.bundle_update_unavailable, bundle.getName()))
|
||||
}
|
||||
}
|
||||
}
|
@ -16,7 +16,7 @@ class DeveloperOptionsViewModel(
|
||||
private val patchBundleRepository: PatchBundleRepository
|
||||
) : ViewModel() {
|
||||
fun redownloadBundles() = viewModelScope.launch {
|
||||
uiSafe(app, R.string.patches_download_fail, RemotePatchBundle.updateFailMsg) {
|
||||
uiSafe(app, R.string.source_download_fail, RemotePatchBundle.updateFailMsg) {
|
||||
patchBundleRepository.redownloadRemoteBundles()
|
||||
}
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ sealed class ResetDialogState(
|
||||
)
|
||||
|
||||
class PatchSelectionBundle(dialogOptionName: String, onConfirm: () -> Unit) : ResetDialogState(
|
||||
titleResId = R.string.patch_selection_reset_patches,
|
||||
descriptionResId = R.string.patch_selection_reset_patches_dialog_description,
|
||||
titleResId = R.string.patch_selection_reset_bundle,
|
||||
descriptionResId = R.string.patch_selection_reset_bundle_dialog_description,
|
||||
onConfirm = onConfirm,
|
||||
dialogOptionName = dialogOptionName
|
||||
)
|
||||
@ -81,8 +81,8 @@ sealed class ResetDialogState(
|
||||
)
|
||||
|
||||
class PatchOptionBundle(dialogOptionName: String, onConfirm: () -> Unit) : ResetDialogState(
|
||||
titleResId = R.string.patch_options_reset,
|
||||
descriptionResId = R.string.patch_options_reset_dialog_description,
|
||||
titleResId = R.string.patch_options_reset_bundle,
|
||||
descriptionResId = R.string.patch_options_reset_bundle_dialog_description,
|
||||
onConfirm = onConfirm,
|
||||
dialogOptionName = dialogOptionName
|
||||
)
|
||||
|
@ -14,24 +14,26 @@
|
||||
<string name="dashboard">Dashboard</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="select_app">Select an app</string>
|
||||
<string name="patches_count_selected">%1$d/%2$d selected</string>
|
||||
<string name="patches_selected">%1$d/%2$d selected</string>
|
||||
|
||||
<string name="new_downloader_plugins_notification">New downloader plugins available. Click here to configure them.</string>
|
||||
<string name="unsupported_architecture_warning">Patching on this device architecture is unsupported and will most likely fail.</string>
|
||||
|
||||
<string name="import_">Import</string>
|
||||
<string name="import_patches">Import patches</string>
|
||||
<string name="import_bundle">Import patch bundle</string>
|
||||
<string name="bundle_patches">Bundle patches</string>
|
||||
<string name="patch_bundle_field">Patch bundle</string>
|
||||
<string name="file_field_set">Selected</string>
|
||||
<string name="file_field_not_set">Not selected</string>
|
||||
|
||||
<string name="field_not_set">Not set</string>
|
||||
|
||||
<string name="patches_missing">Missing</string>
|
||||
<string name="patches_error">Error</string>
|
||||
<string name="patches_error_description">Patches could not be loaded. Click to view the error</string>
|
||||
<string name="patches_not_downloaded">Patches has not been downloaded. Click here to download it</string>
|
||||
<string name="patches_name_default">Patches</string>
|
||||
<string name="patches_name_fallback">Unnamed</string>
|
||||
<string name="bundle_missing">Missing</string>
|
||||
<string name="bundle_error">Error</string>
|
||||
<string name="bundle_error_description">Bundle could not be loaded. Click to view the error</string>
|
||||
<string name="bundle_not_downloaded">Bundle has not been downloaded. Click here to download it</string>
|
||||
<string name="bundle_name_default">Default</string>
|
||||
<string name="bundle_name_fallback">Unnamed</string>
|
||||
|
||||
<string name="android_11_bug_dialog_title">Android 11 bug</string>
|
||||
<string name="android_11_bug_dialog_description">The app installation permission must be granted ahead of time to avoid a bug in the Android 11 system that will negatively affect the user experience.</string>
|
||||
@ -137,15 +139,16 @@
|
||||
<string name="patch_selection_reset_package">Reset patch selection for app</string>
|
||||
<string name="patch_selection_reset_package_dialog_description">You are about to reset the patch selection for the app \"%s\". You will have to manually select each patch again.</string>
|
||||
<string name="patch_selection_reset_package_description">Resets patch selection for a single app</string>
|
||||
<string name="patch_selection_reset_patches">Resets patch selection for a specific patches</string>
|
||||
<string name="patch_selection_reset_patches_dialog_description">You are about to reset the patch selection for \"%s\". You will have to manually select each patch again.</string>
|
||||
<string name="patch_selection_reset_patches_description">Resets the patch selection for a specific patches</string>
|
||||
<string name="patch_selection_reset_bundle">Resets patch selection for bundle</string>
|
||||
<string name="patch_selection_reset_bundle_dialog_description">You are about to reset the patch selection for the bundle \"%s\". You will have to manually select each patch again.</string>
|
||||
<string name="patch_selection_reset_bundle_description">Resets the patch selection for all patches in a bundle</string>
|
||||
<string name="patch_options_reset_package">Reset patch options for app</string>
|
||||
<string name="patch_options_reset_package_dialog_description">You are about to reset the patch options for the app \"%s\". You will have to reapply each option again.</string>
|
||||
<string name="patch_options_reset_package_description">Resets patch options for a single app</string>
|
||||
<string name="patch_options_reset">Reset patch options</string>
|
||||
<string name="patch_options_reset_dialog_description">You are about to reset the patch options for \"%s\". You will have to reapply each option again.</string>
|
||||
<string name="patch_options_reset_all">Reset patch options for all</string>
|
||||
<string name="patch_options_reset_bundle">Resets patch options for bundle</string>
|
||||
<string name="patch_options_reset_bundle_dialog_description">You are about to reset the patch options for the bundle \"%s\". You will have to reapply each option again.</string>
|
||||
<string name="patch_options_reset_bundle_description">Resets patch options for all patches in a bundle</string>
|
||||
<string name="patch_options_reset_all">Reset patch options</string>
|
||||
<string name="patch_options_reset_all_dialog_description">You are about to reset patch options. You will have to reapply each option again.</string>
|
||||
<string name="patch_options_reset_all_description">Resets all patch options</string>
|
||||
<string name="downloader_plugins">Plugins</string>
|
||||
@ -161,7 +164,7 @@
|
||||
|
||||
<string name="search_apps">Search apps…</string>
|
||||
<string name="loading_body">Loading…</string>
|
||||
<string name="downloading_patches">Downloading patches…</string>
|
||||
<string name="downloading_patches">Downloading patch bundle…</string>
|
||||
|
||||
<string name="options">Options</string>
|
||||
<string name="ok">OK</string>
|
||||
@ -199,8 +202,8 @@
|
||||
<string name="debug_logs_export_success">Exported logs</string>
|
||||
<string name="api_url">API URL</string>
|
||||
<string name="api_url_description">The API used to download necessary files.</string>
|
||||
<string name="api_url_dialog_title">Change API URL</string>
|
||||
<string name="api_url_dialog_description">Change the API URL of ReVanced Manager. ReVanced Manager uses the API to download patches and updates.</string>
|
||||
<string name="api_url_dialog_title">Set custom API URL</string>
|
||||
<string name="api_url_dialog_description">Set the API URL of ReVanced Manager. ReVanced Manager uses the API to download patches and updates.</string>
|
||||
<string name="api_url_dialog_warning">ReVanced Manager connects to the API to download patches and updates. Make sure that you trust it.</string>
|
||||
<string name="api_url_dialog_save">Set</string>
|
||||
<string name="api_url_dialog_reset">Reset API URL</string>
|
||||
@ -210,25 +213,26 @@
|
||||
<string name="device_architectures">CPU Architectures</string>
|
||||
<string name="device_memory_limit">Memory limits</string>
|
||||
<string name="device_memory_limit_format">%1$dMB (Normal) - %2$dMB (Large)</string>
|
||||
<string name="patches_force_download">Force download all patches</string>
|
||||
<string name="patches_reset">Reset patches</string>
|
||||
<string name="patch_bundles_section">Patch bundles</string>
|
||||
<string name="patch_bundles_force_download">Force download all patch bundles</string>
|
||||
<string name="patch_bundles_reset">Reset patch bundles</string>
|
||||
<string name="patching">Patching</string>
|
||||
<string name="signing">Signing</string>
|
||||
<string name="storage">Storage</string>
|
||||
<string name="no_patch_found">No patch can be found. Check your patches</string>
|
||||
<string name="patches_unavailable">No patches are available. Check your bundles</string>
|
||||
<string name="tab_apps">Apps</string>
|
||||
<string name="tab_patches">Patches</string>
|
||||
<string name="tab_bundles">Patch bundles</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="refresh">Refresh</string>
|
||||
<string name="continue_anyways">Continue anyways</string>
|
||||
<string name="download_another_version">Download another version</string>
|
||||
<string name="download_app">Download app</string>
|
||||
<string name="download_apk">Download APK file</string>
|
||||
<string name="patches_download_fail">Failed to download patches: %s</string>
|
||||
<string name="patches_replace_fail">Failed to load updated patches: %s</string>
|
||||
<string name="source_download_fail">Failed to download patch bundle: %s</string>
|
||||
<string name="source_replace_fail">Failed to load updated patch bundle: %s</string>
|
||||
<string name="no_patched_apps_found">No patched apps found</string>
|
||||
<string name="tap_on_patches">Tap on the patches to get more information about them</string>
|
||||
<string name="patches_selected">%s selected</string>
|
||||
<string name="bundles_selected">%s selected</string>
|
||||
<string name="incompatible_patches">Incompatible patches</string>
|
||||
<string name="universal_patches">Universal patches</string>
|
||||
<string name="patch_selection_reset_toast">Patch selection and options has been reset to recommended defaults</string>
|
||||
@ -344,13 +348,20 @@
|
||||
<string name="submit_feedback_description">Help us improve this application</string>
|
||||
<string name="developer_options">Developer options</string>
|
||||
<string name="developer_options_description">Options for debugging issues</string>
|
||||
<string name="patches_update_success">Successfully updated %s</string>
|
||||
<string name="patches_update_unavailable">No update available for %s</string>
|
||||
<string name="view_patches">View patches</string>
|
||||
<string name="patches_view_any_version">Any version</string>
|
||||
<string name="patches_view_any_package">Any package</string>
|
||||
<string name="patches_delete_single_dialog_description">Are you sure you want to delete \"%s\"?</string>
|
||||
<string name="patches_delete_multiple_dialog_description">Are you sure you want to delete the selected patches?</string>
|
||||
<string name="bundle_input_source_url">Source URL</string>
|
||||
<string name="bundle_update_success">Successfully updated %s</string>
|
||||
<string name="bundle_update_unavailable">No update available for %s</string>
|
||||
<string name="bundle_auto_update">Auto update</string>
|
||||
<string name="bundle_auto_update_description">Automatically update this bundle when ReVanced starts</string>
|
||||
<string name="bundle_view_patches">View patches</string>
|
||||
<string name="bundle_view_all_patches">View all %d patches</string>
|
||||
<string name="bundle_view_patches_any_version">Any version</string>
|
||||
<string name="bundle_view_patches_any_package">Any package</string>
|
||||
<string name="bundle_delete_single_dialog_title">Delete bundle</string>
|
||||
<string name="bundle_delete_multiple_dialog_title">Delete bundles</string>
|
||||
<string name="bundle_delete_single_dialog_description">Are you sure you want to delete the bundle \"%s\"?</string>
|
||||
<string name="bundle_delete_multiple_dialog_description">Are you sure you want to delete the selected bundles?</string>
|
||||
|
||||
|
||||
<string name="about_revanced_manager">About ReVanced Manager</string>
|
||||
<string name="revanced_manager_description">ReVanced Manager is an Android application that uses ReVanced Patcher to patch Android apps. It allows you to download and patch apps with custom patches, and manage the patching process.</string>
|
||||
@ -404,9 +415,10 @@
|
||||
<string name="no_contributors_found">No contributors found</string>
|
||||
<string name="select">Select</string>
|
||||
<string name="select_deselect_all">Select or deselect all</string>
|
||||
<string name="select_patches_type_dialog_description">Add new patches from URL or local files</string>
|
||||
<string name="local_patches_description">Add patches from local storage.</string>
|
||||
<string name="remote_patches_description">Add patches from URL. Patches can automatically update.</string>
|
||||
<string name="select_bundle_type_dialog_title">Add new bundle</string>
|
||||
<string name="select_bundle_type_dialog_description">Add a new bundle from a URL or storage</string>
|
||||
<string name="local_bundle_description">Import local files from your storage, does not automatically update</string>
|
||||
<string name="remote_bundle_description">Import remote files from a URL, can automatically update</string>
|
||||
<string name="recommended">Recommended</string>
|
||||
|
||||
<string name="installation_failed_dialog_title">Installation failed</string>
|
||||
@ -431,10 +443,9 @@
|
||||
<string name="about_device">About device</string>
|
||||
<string name="enter_url">Enter URL</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="add_patch_bundle">Add patch bundle</string>
|
||||
<string name="bundle_url">Bundle URL</string>
|
||||
<string name="auto_update">Auto update</string>
|
||||
<string name="add_patches">Add patches</string>
|
||||
<string name="auto_update_description">Automatically update when a new version is available</string>
|
||||
<string name="patches_url">Patches URL</string>
|
||||
<string name="incompatible_patches_dialog">These patches are not compatible with the selected app version (%1$s).\n\nClick on the patches to see more details.</string>
|
||||
<string name="incompatible_patch">Incompatible patch</string>
|
||||
<string name="any_version">Any</string>
|
||||
|
Reference in New Issue
Block a user