mirror of
https://github.com/revanced/revanced-manager.git
synced 2025-04-30 14:04:26 +02:00
feat: Improve patch bundle screen (#2070)
This commit is contained in:
parent
747017a5f9
commit
edb4e421e2
@ -2,37 +2,33 @@ package app.revanced.manager.ui.component.bundle
|
|||||||
|
|
||||||
import android.webkit.URLUtil
|
import android.webkit.URLUtil
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.outlined.ArrowRight
|
import androidx.compose.material.icons.automirrored.outlined.ArrowRight
|
||||||
import androidx.compose.material3.FilledTonalButton
|
import androidx.compose.material.icons.outlined.Extension
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material.icons.outlined.Inventory2
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material.icons.outlined.Sell
|
||||||
import androidx.compose.material3.Switch
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.pluralStringResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import app.revanced.manager.R
|
import app.revanced.manager.R
|
||||||
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
import app.revanced.manager.ui.component.ColumnWithScrollbar
|
||||||
import app.revanced.manager.ui.component.TextInputDialog
|
import app.revanced.manager.ui.component.TextInputDialog
|
||||||
import app.revanced.manager.util.isDebuggable
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BaseBundleDialog(
|
fun BaseBundleDialog(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
isDefault: Boolean,
|
isDefault: Boolean,
|
||||||
name: String?,
|
name: String?,
|
||||||
onNameChange: ((String) -> Unit)? = null,
|
|
||||||
remoteUrl: String?,
|
remoteUrl: String?,
|
||||||
onRemoteUrlChange: ((String) -> Unit)? = null,
|
onRemoteUrlChange: ((String) -> Unit)? = null,
|
||||||
patchCount: Int,
|
patchCount: Int,
|
||||||
@ -40,39 +36,66 @@ fun BaseBundleDialog(
|
|||||||
autoUpdate: Boolean,
|
autoUpdate: Boolean,
|
||||||
onAutoUpdateChange: (Boolean) -> Unit,
|
onAutoUpdateChange: (Boolean) -> Unit,
|
||||||
onPatchesClick: () -> Unit,
|
onPatchesClick: () -> Unit,
|
||||||
onBundleTypeClick: () -> Unit = {},
|
|
||||||
extraFields: @Composable ColumnScope.() -> Unit = {}
|
extraFields: @Composable ColumnScope.() -> Unit = {}
|
||||||
) {
|
) {
|
||||||
ColumnWithScrollbar(
|
ColumnWithScrollbar(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.then(modifier)
|
.then(modifier),
|
||||||
) {
|
) {
|
||||||
if (name != null) {
|
Column(
|
||||||
var showNameInputDialog by rememberSaveable {
|
modifier = Modifier.padding(16.dp),
|
||||||
mutableStateOf(false)
|
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||||
}
|
) {
|
||||||
if (showNameInputDialog) {
|
Row(
|
||||||
TextInputDialog(
|
modifier = Modifier.fillMaxWidth(),
|
||||||
initial = name,
|
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start),
|
||||||
title = stringResource(R.string.bundle_input_name),
|
verticalAlignment = Alignment.CenterVertically
|
||||||
onDismissRequest = {
|
) {
|
||||||
showNameInputDialog = false
|
Icon(
|
||||||
},
|
imageVector = Icons.Outlined.Inventory2,
|
||||||
onConfirm = {
|
contentDescription = null,
|
||||||
showNameInputDialog = false
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
onNameChange?.invoke(it)
|
modifier = Modifier.size(32.dp)
|
||||||
},
|
|
||||||
validator = {
|
|
||||||
it.length in 1..19
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
name?.let {
|
||||||
|
Text(
|
||||||
|
text = it,
|
||||||
|
style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight(800)),
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = 2.dp)
|
||||||
|
) {
|
||||||
|
version?.let {
|
||||||
|
Tag(Icons.Outlined.Sell, it)
|
||||||
|
}
|
||||||
|
Tag(Icons.Outlined.Extension, patchCount.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HorizontalDivider(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
color = MaterialTheme.colorScheme.outlineVariant
|
||||||
|
)
|
||||||
|
|
||||||
|
if (remoteUrl != null) {
|
||||||
BundleListItem(
|
BundleListItem(
|
||||||
headlineText = stringResource(R.string.bundle_input_name),
|
headlineText = stringResource(R.string.bundle_auto_update),
|
||||||
supportingText = name.ifEmpty { stringResource(R.string.field_not_set) },
|
supportingText = stringResource(R.string.bundle_auto_update_description),
|
||||||
modifier = Modifier.clickable(enabled = onNameChange != null) {
|
trailingContent = {
|
||||||
showNameInputDialog = true
|
Switch(
|
||||||
|
checked = autoUpdate,
|
||||||
|
onCheckedChange = onAutoUpdateChange
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
onAutoUpdateChange(!autoUpdate)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -99,81 +122,59 @@ fun BaseBundleDialog(
|
|||||||
}
|
}
|
||||||
|
|
||||||
BundleListItem(
|
BundleListItem(
|
||||||
modifier = Modifier.clickable(enabled = onRemoteUrlChange != null) {
|
modifier = Modifier.clickable(
|
||||||
showUrlInputDialog = true
|
enabled = onRemoteUrlChange != null,
|
||||||
},
|
onClick = {
|
||||||
headlineText = stringResource(R.string.bundle_input_source_url),
|
showUrlInputDialog = true
|
||||||
supportingText = url.ifEmpty { stringResource(R.string.field_not_set) }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
extraFields()
|
|
||||||
|
|
||||||
if (remoteUrl != null) {
|
|
||||||
BundleListItem(
|
|
||||||
headlineText = stringResource(R.string.bundle_auto_update),
|
|
||||||
supportingText = stringResource(R.string.bundle_auto_update_description),
|
|
||||||
trailingContent = {
|
|
||||||
Switch(
|
|
||||||
checked = autoUpdate,
|
|
||||||
onCheckedChange = onAutoUpdateChange
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier.clickable {
|
|
||||||
onAutoUpdateChange(!autoUpdate)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
BundleListItem(
|
|
||||||
headlineText = stringResource(R.string.bundle_type),
|
|
||||||
supportingText = stringResource(R.string.bundle_type_description),
|
|
||||||
modifier = Modifier.clickable {
|
|
||||||
onBundleTypeClick()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
FilledTonalButton(
|
|
||||||
onClick = onBundleTypeClick,
|
|
||||||
content = {
|
|
||||||
if (remoteUrl == null) {
|
|
||||||
Text(stringResource(R.string.local))
|
|
||||||
} else {
|
|
||||||
Text(stringResource(R.string.remote))
|
|
||||||
}
|
}
|
||||||
|
),
|
||||||
|
headlineText = stringResource(R.string.bundle_input_source_url),
|
||||||
|
supportingText = url.ifEmpty {
|
||||||
|
stringResource(R.string.field_not_set)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version != null || patchCount > 0) {
|
val patchesClickable = patchCount > 0
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.information),
|
|
||||||
modifier = Modifier.padding(
|
|
||||||
horizontal = 16.dp,
|
|
||||||
vertical = 12.dp
|
|
||||||
),
|
|
||||||
style = MaterialTheme.typography.labelLarge,
|
|
||||||
color = MaterialTheme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val patchesClickable = LocalContext.current.isDebuggable && patchCount > 0
|
|
||||||
BundleListItem(
|
BundleListItem(
|
||||||
headlineText = stringResource(R.string.patches),
|
headlineText = stringResource(R.string.patches),
|
||||||
supportingText = pluralStringResource(R.plurals.bundle_patches_available, patchCount, patchCount),
|
supportingText = stringResource(R.string.bundle_view_patches),
|
||||||
modifier = Modifier.clickable(enabled = patchesClickable, onClick = onPatchesClick)
|
modifier = Modifier.clickable(
|
||||||
|
enabled = patchesClickable,
|
||||||
|
onClick = onPatchesClick
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
if (patchesClickable)
|
if (patchesClickable) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.AutoMirrored.Outlined.ArrowRight,
|
Icons.AutoMirrored.Outlined.ArrowRight,
|
||||||
stringResource(R.string.patches)
|
stringResource(R.string.patches)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version?.let {
|
extraFields()
|
||||||
BundleListItem(
|
}
|
||||||
headlineText = stringResource(R.string.version),
|
}
|
||||||
supportingText = it,
|
|
||||||
)
|
@Composable
|
||||||
}
|
private fun Tag(
|
||||||
|
icon: ImageVector,
|
||||||
|
text: String
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
tint = MaterialTheme.colorScheme.outline,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.outline,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -11,18 +11,9 @@ import androidx.compose.material.icons.automirrored.outlined.ArrowRight
|
|||||||
import androidx.compose.material.icons.outlined.DeleteOutline
|
import androidx.compose.material.icons.outlined.DeleteOutline
|
||||||
import androidx.compose.material.icons.outlined.Share
|
import androidx.compose.material.icons.outlined.Share
|
||||||
import androidx.compose.material.icons.outlined.Update
|
import androidx.compose.material.icons.outlined.Update
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
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.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -78,7 +69,7 @@ fun BundleInformationDialog(
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
BundleTopBar(
|
BundleTopBar(
|
||||||
title = bundleName,
|
title = stringResource(R.string.patch_bundle_field),
|
||||||
onBackClick = onDismissRequest,
|
onBackClick = onDismissRequest,
|
||||||
backIcon = {
|
backIcon = {
|
||||||
Icon(
|
Icon(
|
||||||
@ -111,7 +102,6 @@ fun BundleInformationDialog(
|
|||||||
modifier = Modifier.padding(paddingValues),
|
modifier = Modifier.padding(paddingValues),
|
||||||
isDefault = bundle.isDefault,
|
isDefault = bundle.isDefault,
|
||||||
name = bundleName,
|
name = bundleName,
|
||||||
onNameChange = { composableScope.launch { bundle.setName(it) } },
|
|
||||||
remoteUrl = bundle.asRemoteOrNull?.endpoint,
|
remoteUrl = bundle.asRemoteOrNull?.endpoint,
|
||||||
patchCount = patchCount,
|
patchCount = patchCount,
|
||||||
version = props?.versionInfo?.patches,
|
version = props?.versionInfo?.patches,
|
||||||
|
@ -11,8 +11,4 @@
|
|||||||
<plurals name="selected_count">
|
<plurals name="selected_count">
|
||||||
<item quantity="other">%d selected</item>
|
<item quantity="other">%d selected</item>
|
||||||
</plurals>
|
</plurals>
|
||||||
<plurals name="bundle_patches_available">
|
|
||||||
<item quantity="one">%d patch available</item>
|
|
||||||
<item quantity="other">%d patches available</item>
|
|
||||||
</plurals>
|
|
||||||
</resources>
|
</resources>
|
@ -145,7 +145,6 @@
|
|||||||
<string name="close">Close</string>
|
<string name="close">Close</string>
|
||||||
<string name="system">System</string>
|
<string name="system">System</string>
|
||||||
<string name="light">Light</string>
|
<string name="light">Light</string>
|
||||||
<string name="information">Information</string>
|
|
||||||
<string name="dark">Dark</string>
|
<string name="dark">Dark</string>
|
||||||
<string name="appearance">Appearance</string>
|
<string name="appearance">Appearance</string>
|
||||||
<string name="downloaded_apps">Downloaded apps</string>
|
<string name="downloaded_apps">Downloaded apps</string>
|
||||||
@ -181,8 +180,6 @@
|
|||||||
<string name="tab_bundles">Patch bundles</string>
|
<string name="tab_bundles">Patch bundles</string>
|
||||||
<string name="delete">Delete</string>
|
<string name="delete">Delete</string>
|
||||||
<string name="refresh">Refresh</string>
|
<string name="refresh">Refresh</string>
|
||||||
<string name="remote">Remote</string>
|
|
||||||
<string name="local">Local</string>
|
|
||||||
<string name="continue_anyways">Continue anyways</string>
|
<string name="continue_anyways">Continue anyways</string>
|
||||||
<string name="download_another_version">Download another version</string>
|
<string name="download_another_version">Download another version</string>
|
||||||
<string name="download_app">Download app</string>
|
<string name="download_app">Download app</string>
|
||||||
@ -302,14 +299,12 @@
|
|||||||
<string name="submit_feedback_description">Help us improve this application</string>
|
<string name="submit_feedback_description">Help us improve this application</string>
|
||||||
<string name="developer_options">Developer options</string>
|
<string name="developer_options">Developer options</string>
|
||||||
<string name="developer_options_description">Options for debugging issues</string>
|
<string name="developer_options_description">Options for debugging issues</string>
|
||||||
<string name="bundle_input_name">Name</string>
|
|
||||||
<string name="bundle_input_source_url">Source URL</string>
|
<string name="bundle_input_source_url">Source URL</string>
|
||||||
<string name="bundle_update_success">Successfully updated %s</string>
|
<string name="bundle_update_success">Successfully updated %s</string>
|
||||||
<string name="bundle_update_unavailable">No update available for %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">Auto update</string>
|
||||||
<string name="bundle_auto_update_description">Automatically update this bundle when ReVanced starts</string>
|
<string name="bundle_auto_update_description">Automatically update this bundle when ReVanced starts</string>
|
||||||
<string name="bundle_type">Bundle type</string>
|
<string name="bundle_view_patches">View patches</string>
|
||||||
<string name="bundle_type_description">Choose the type of bundle you want</string>
|
|
||||||
<string name="about_revanced_manager">About ReVanced Manager</string>
|
<string name="about_revanced_manager">About ReVanced Manager</string>
|
||||||
<string name="revanced_manager_description">ReVanced Manager is an application designed to work with ReVanced Patcher, which allows for long-lasting patches to be created for Android apps. The patching system is designed to automatically work with new versions of apps with minimal maintenance.</string>
|
<string name="revanced_manager_description">ReVanced Manager is an application designed to work with ReVanced Patcher, which allows for long-lasting patches to be created for Android apps. The patching system is designed to automatically work with new versions of apps with minimal maintenance.</string>
|
||||||
<string name="update_available">An update is available</string>
|
<string name="update_available">An update is available</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user