From 55524f7284a44bbf8e8c782eedd7fc06d54944cf Mon Sep 17 00:00:00 2001 From: brosssh <44944126+brosssh@users.noreply.github.com> Date: Tue, 8 Jul 2025 20:23:03 +0200 Subject: [PATCH] feat: Improve bundle info screen design (#2548) --- .../domain/bundles/LocalPatchBundle.kt | 2 +- .../domain/bundles/PatchBundleSource.kt | 4 +- .../manager/patcher/patch/PatchBundle.kt | 28 +++++- .../ui/component/bundle/BaseBundleDialog.kt | 99 +++++++++++-------- .../bundle/BundleInformationDialog.kt | 7 +- .../revanced/manager/ui/model/BundleInfo.kt | 4 +- app/src/main/res/values/strings.xml | 1 + 7 files changed, 93 insertions(+), 52 deletions(-) diff --git a/app/src/main/java/app/revanced/manager/domain/bundles/LocalPatchBundle.kt b/app/src/main/java/app/revanced/manager/domain/bundles/LocalPatchBundle.kt index 2fcac8d3..a940e05d 100644 --- a/app/src/main/java/app/revanced/manager/domain/bundles/LocalPatchBundle.kt +++ b/app/src/main/java/app/revanced/manager/domain/bundles/LocalPatchBundle.kt @@ -15,7 +15,7 @@ class LocalPatchBundle(name: String, id: Int, directory: File) : } reload()?.also { - saveVersionHash(it.readManifestAttribute("Version")) + saveVersionHash(it.patchBundleManifestAttributes?.version) } } } diff --git a/app/src/main/java/app/revanced/manager/domain/bundles/PatchBundleSource.kt b/app/src/main/java/app/revanced/manager/domain/bundles/PatchBundleSource.kt index ee46cc71..1bc8a7f8 100644 --- a/app/src/main/java/app/revanced/manager/domain/bundles/PatchBundleSource.kt +++ b/app/src/main/java/app/revanced/manager/domain/bundles/PatchBundleSource.kt @@ -38,7 +38,7 @@ sealed class PatchBundleSource(initialName: String, val uid: Int, directory: Fil suspend fun getName() = nameFlow.first() - val versionFlow = state.map { it.patchBundleOrNull()?.readManifestAttribute("Version") } + val versionFlow = state.map { it.patchBundleOrNull()?.patchBundleManifestAttributes?.version } val patchCountFlow = state.map { it.patchBundleOrNull()?.patches?.size ?: 0 } /** @@ -74,7 +74,7 @@ sealed class PatchBundleSource(initialName: String, val uid: Int, directory: Fil val bundle = newState.patchBundleOrNull() // Try to read the name from the patch bundle manifest if the bundle does not have a name. if (bundle != null && _nameFlow.value.isEmpty()) { - bundle.readManifestAttribute("Name")?.let { setName(it) } + bundle.patchBundleManifestAttributes?.name?.let { setName(it) } } return bundle diff --git a/app/src/main/java/app/revanced/manager/patcher/patch/PatchBundle.kt b/app/src/main/java/app/revanced/manager/patcher/patch/PatchBundle.kt index 2b93a829..e894f748 100644 --- a/app/src/main/java/app/revanced/manager/patcher/patch/PatchBundle.kt +++ b/app/src/main/java/app/revanced/manager/patcher/patch/PatchBundle.kt @@ -8,6 +8,17 @@ import java.io.File import java.io.IOException import java.util.jar.JarFile +class PatchBundleManifestAttributes( + val name: String?, + val version: String?, + val description: String?, + val source: String?, + val author: String?, + val contact: String?, + val website: String?, + val license: String? +) + class PatchBundle(val patchesJar: File) { private val loader = object : Iterable> { private fun load(): Iterable> { @@ -36,7 +47,20 @@ class PatchBundle(val patchesJar: File) { null } - fun readManifestAttribute(name: String) = manifest?.mainAttributes?.getValue(name) + val patchBundleManifestAttributes = if(manifest != null) + PatchBundleManifestAttributes( + name = readManifestAttribute("name"), + version = readManifestAttribute("version"), + description = readManifestAttribute("description"), + source = readManifestAttribute("source"), + author = readManifestAttribute("author"), + contact = readManifestAttribute("contact"), + website = readManifestAttribute("website"), + license = readManifestAttribute("license") + ) else + null + + private fun readManifestAttribute(name: String) = manifest?.mainAttributes?.getValue(name)?.takeIf { it.isNotBlank() } // If empty, set it to null instead. /** * Load all patches compatible with the specified package. @@ -53,4 +77,4 @@ class PatchBundle(val patchesJar: File) { true } -} \ No newline at end of file +} diff --git a/app/src/main/java/app/revanced/manager/ui/component/bundle/BaseBundleDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/bundle/BaseBundleDialog.kt index dfc63735..0ec27d8d 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/bundle/BaseBundleDialog.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/bundle/BaseBundleDialog.kt @@ -2,13 +2,26 @@ package app.revanced.manager.ui.component.bundle import android.webkit.URLUtil import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowRight -import androidx.compose.material.icons.outlined.Extension -import androidx.compose.material.icons.outlined.Inventory2 +import androidx.compose.material.icons.automirrored.outlined.Send +import androidx.compose.material.icons.outlined.Commit +import androidx.compose.material.icons.outlined.Description +import androidx.compose.material.icons.outlined.Gavel +import androidx.compose.material.icons.outlined.Language +import androidx.compose.material.icons.outlined.Person import androidx.compose.material.icons.outlined.Sell -import androidx.compose.material3.* +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -17,10 +30,11 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import app.revanced.manager.R +import app.revanced.manager.patcher.patch.PatchBundleManifestAttributes import app.revanced.manager.ui.component.ColumnWithScrollbar import app.revanced.manager.ui.component.TextInputDialog import app.revanced.manager.ui.component.haptics.HapticSwitch @@ -29,12 +43,12 @@ import app.revanced.manager.ui.component.haptics.HapticSwitch fun BaseBundleDialog( modifier: Modifier = Modifier, isDefault: Boolean, - name: String?, remoteUrl: String?, onRemoteUrlChange: ((String) -> Unit)? = null, patchCount: Int, version: String?, autoUpdate: Boolean, + bundleManifestAttributes: PatchBundleManifestAttributes?, onAutoUpdateChange: (Boolean) -> Unit, onPatchesClick: () -> Unit, extraFields: @Composable ColumnScope.() -> Unit = {} @@ -48,35 +62,26 @@ fun BaseBundleDialog( modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(4.dp) ) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.Start), - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = Icons.Outlined.Inventory2, - contentDescription = null, - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(32.dp) - ) - name?.let { - Text( - text = it, - style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight(800)), - color = MaterialTheme.colorScheme.primary, - ) - } + version?.let { + Tag(Icons.Outlined.Sell, it) } - 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()) + bundleManifestAttributes?.description?.let { + Tag(Icons.Outlined.Description, it) + } + bundleManifestAttributes?.source?.let { + Tag(Icons.Outlined.Commit, it) + } + bundleManifestAttributes?.author?.let { + Tag(Icons.Outlined.Person, it) + } + bundleManifestAttributes?.contact?.let { + Tag(Icons.AutoMirrored.Outlined.Send, it) + } + bundleManifestAttributes?.website?.let { + Tag(Icons.Outlined.Language, it, isUrl = true) + } + bundleManifestAttributes?.license?.let { + Tag(Icons.Outlined.Gavel, it) } } @@ -138,8 +143,8 @@ fun BaseBundleDialog( val patchesClickable = patchCount > 0 BundleListItem( - headlineText = stringResource(R.string.patches), - supportingText = stringResource(R.string.bundle_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 @@ -160,22 +165,34 @@ fun BaseBundleDialog( @Composable private fun Tag( icon: ImageVector, - text: String + text: String, + isUrl: Boolean = false ) { + val uriHandler = LocalUriHandler.current + Row( horizontalArrangement = Arrangement.spacedBy(6.dp), - verticalAlignment = Alignment.CenterVertically + verticalAlignment = Alignment.CenterVertically, + modifier = if (isUrl) { + Modifier + .clickable { + try { + uriHandler.openUri(text) + } catch (_: Exception) {} + } + } + else + Modifier, ) { Icon( imageVector = icon, contentDescription = null, - modifier = Modifier.size(16.dp), - tint = MaterialTheme.colorScheme.outline, + modifier = Modifier.size(16.dp) ) Text( text, style = MaterialTheme.typography.bodyMedium, - color = MaterialTheme.colorScheme.outline, + color = if(isUrl) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.outline, ) } } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleInformationDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleInformationDialog.kt index 15f5eae1..1e86aced 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleInformationDialog.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/bundle/BundleInformationDialog.kt @@ -44,13 +44,14 @@ fun BundleInformationDialog( }.collectAsStateWithLifecycle(null) val patchCount by bundle.patchCountFlow.collectAsStateWithLifecycle(0) val version by bundle.versionFlow.collectAsStateWithLifecycle(null) + val bundleManifestAttributes = state.patchBundleOrNull()?.patchBundleManifestAttributes if (viewCurrentBundlePatches) { BundlePatchesDialog( onDismissRequest = { viewCurrentBundlePatches = false }, - bundle = bundle, + bundle = bundle ) } @@ -62,7 +63,7 @@ fun BundleInformationDialog( Scaffold( topBar = { BundleTopBar( - title = stringResource(R.string.patch_bundle_field), + title = bundleName, onBackClick = onDismissRequest, backIcon = { Icon( @@ -94,11 +95,11 @@ fun BundleInformationDialog( BaseBundleDialog( modifier = Modifier.padding(paddingValues), isDefault = bundle.isDefault, - name = bundleName, remoteUrl = bundle.asRemoteOrNull?.endpoint, patchCount = patchCount, version = version, autoUpdate = props?.autoUpdate == true, + bundleManifestAttributes = bundleManifestAttributes, onAutoUpdateChange = { composableScope.launch { bundle.asRemoteOrNull?.setAutoUpdate(it) diff --git a/app/src/main/java/app/revanced/manager/ui/model/BundleInfo.kt b/app/src/main/java/app/revanced/manager/ui/model/BundleInfo.kt index cfef366f..0fb01a76 100644 --- a/app/src/main/java/app/revanced/manager/ui/model/BundleInfo.kt +++ b/app/src/main/java/app/revanced/manager/ui/model/BundleInfo.kt @@ -23,8 +23,6 @@ data class BundleInfo( yieldAll(universal) } - val patchCount get() = compatible.size + incompatible.size + universal.size - fun patchSequence(allowIncompatible: Boolean) = if (allowIncompatible) { all } else { @@ -79,7 +77,7 @@ data class BundleInfo( targetList.add(it) } - BundleInfo(source.getName(), bundle.readManifestAttribute("Version"), source.uid, compatible, incompatible, universal) + BundleInfo(source.getName(), bundle.patchBundleManifestAttributes?.version, source.uid, compatible, incompatible, universal) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 253de2df..31730c8c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -354,6 +354,7 @@ Auto update Automatically update this bundle when ReVanced starts View patches + View all %d patches Any version Any package Delete bundle