feat: Improve patch bundle screen (#2070)

This commit is contained in:
Ushie 2024-08-17 01:58:43 +03:00 committed by GitHub
parent 747017a5f9
commit edb4e421e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 103 additions and 121 deletions

View File

@ -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 = { name?.let {
it.length in 1..19 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(
enabled = onRemoteUrlChange != null,
onClick = {
showUrlInputDialog = true showUrlInputDialog = true
},
headlineText = stringResource(R.string.bundle_input_source_url),
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))
}
}
)
}
if (version != null || patchCount > 0) {
Text(
text = stringResource(R.string.information),
modifier = Modifier.padding(
horizontal = 16.dp,
vertical = 12.dp
), ),
style = MaterialTheme.typography.labelLarge, headlineText = stringResource(R.string.bundle_input_source_url),
color = MaterialTheme.colorScheme.primary, supportingText = url.ifEmpty {
stringResource(R.string.field_not_set)
}
) )
} }
val patchesClickable = LocalContext.current.isDebuggable && patchCount > 0 val patchesClickable = 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 {
BundleListItem(
headlineText = stringResource(R.string.version),
supportingText = it,
)
} }
extraFields()
}
}
@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,
)
} }
} }

View File

@ -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,

View File

@ -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>

View File

@ -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>