diff --git a/.github/workflows/pr-build.yml b/.github/workflows/pr-build.yml index e4a04351..f912fedb 100644 --- a/.github/workflows/pr-build.yml +++ b/.github/workflows/pr-build.yml @@ -23,8 +23,8 @@ jobs: java-version: '17' distribution: 'temurin' - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 - name: Build with Gradle env: @@ -38,7 +38,7 @@ jobs: run: mv app/build/outputs/apk/release/app-release.apk revanced-manager-${{ env.COMMIT_HASH }}.apk - name: Upload build - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: revanced-manager path: revanced-manager-${{ env.COMMIT_HASH }}.apk diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 8e273987..9574e59b 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -20,10 +20,8 @@ jobs: java-version: '17' distribution: 'temurin' - - name: Setup Gradle - uses: gradle/gradle-build-action@v2 - with: - cache-disabled: true + - name: Set up Gradle + uses: gradle/actions/setup-gradle@v3 - name: Build with Gradle env: diff --git a/.github/workflows/update-documentation.yml b/.github/workflows/update-documentation.yml index 77097e2f..541a7aa5 100644 --- a/.github/workflows/update-documentation.yml +++ b/.github/workflows/update-documentation.yml @@ -11,7 +11,7 @@ jobs: name: Dispatch event to documentation repository if: github.ref == 'refs/heads/main' steps: - - uses: peter-evans/repository-dispatch@v2 + - uses: peter-evans/repository-dispatch@v3 with: token: ${{ secrets.DOCUMENTATION_REPO_ACCESS_TOKEN }} repository: revanced/revanced-documentation diff --git a/app/src/main/java/app/revanced/manager/ui/component/AlertDialogExtended.kt b/app/src/main/java/app/revanced/manager/ui/component/AlertDialogExtended.kt index 0cfd3453..cceb189f 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/AlertDialogExtended.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/AlertDialogExtended.kt @@ -44,7 +44,7 @@ fun AlertDialogExtended( titleContentColor: Color = AlertDialogDefaults.titleContentColor, textContentColor: Color = AlertDialogDefaults.textContentColor, tonalElevation: Dp = AlertDialogDefaults.TonalElevation, - textHorizontalPadding: PaddingValues = PaddingValues(horizontal = 24.dp) + textHorizontalPadding: PaddingValues = TextHorizontalPadding ) { BasicAlertDialog(onDismissRequest = onDismissRequest) { Surface( @@ -147,4 +147,6 @@ private fun ContentStyle( content() } } -} \ No newline at end of file +} + +val TextHorizontalPadding = PaddingValues(horizontal = 24.dp) \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/component/Markdown.kt b/app/src/main/java/app/revanced/manager/ui/component/Markdown.kt index ec8b3bd0..2b5b276e 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/Markdown.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/Markdown.kt @@ -18,7 +18,8 @@ fun Markdown( colors = markdownColor( text = MaterialTheme.colorScheme.onSurfaceVariant, codeBackground = MaterialTheme.colorScheme.secondaryContainer, - codeText = MaterialTheme.colorScheme.onSecondaryContainer + codeText = MaterialTheme.colorScheme.onSecondaryContainer, + linkText = MaterialTheme.colorScheme.primary ), typography = markdownTypography( h1 = MaterialTheme.typography.headlineSmall.copy(fontWeight = FontWeight.Bold), diff --git a/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleDialog.kt index cb23a36a..2de48a56 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleDialog.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleDialog.kt @@ -4,52 +4,55 @@ import android.net.Uri import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Topic +import androidx.compose.material3.Checkbox import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.Scaffold +import androidx.compose.material3.ListItem +import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.RadioButton import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties import app.revanced.manager.R +import app.revanced.manager.ui.component.AlertDialogExtended +import app.revanced.manager.ui.component.TextHorizontalPadding import app.revanced.manager.ui.model.BundleType import app.revanced.manager.util.APK_MIMETYPE import app.revanced.manager.util.JAR_MIMETYPE -@OptIn(ExperimentalMaterial3Api::class) @Composable -fun ImportBundleDialog( - onDismissRequest: () -> Unit, +fun ImportPatchBundleDialog( + onDismiss: () -> Unit, onRemoteSubmit: (String, Boolean) -> Unit, - onLocalSubmit: (Uri, Uri?) -> Unit, - initialBundleType: BundleType + onLocalSubmit: (Uri, Uri?) -> Unit ) { - var remoteUrl by rememberSaveable { mutableStateOf("") } - var autoUpdate by rememberSaveable { mutableStateOf(true) } - var bundleType by rememberSaveable { mutableStateOf(initialBundleType) } + var currentStep by rememberSaveable { mutableIntStateOf(0) } + var bundleType by rememberSaveable { mutableStateOf(BundleType.Remote) } var patchBundle by rememberSaveable { mutableStateOf(null) } var integrations by rememberSaveable { mutableStateOf(null) } - - val inputsAreValid by remember { - derivedStateOf { - if (bundleType == BundleType.Local) patchBundle != null else remoteUrl.isNotEmpty() - } - } + var remoteUrl by rememberSaveable { mutableStateOf("") } + var autoUpdate by rememberSaveable { mutableStateOf(false) } val patchActivityLauncher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri -> @@ -69,97 +72,208 @@ fun ImportBundleDialog( integrationsActivityLauncher.launch(APK_MIMETYPE) } - Dialog( - onDismissRequest = onDismissRequest, - properties = DialogProperties( - usePlatformDefaultWidth = false, - dismissOnBackPress = true - ) - ) { - Scaffold( - topBar = { - BundleTopBar( - title = stringResource(R.string.import_bundle), - onBackClick = onDismissRequest, - backIcon = { - Icon( - imageVector = Icons.Default.Close, - contentDescription = stringResource(R.string.close) - ) - }, - actions = { - TextButton( - enabled = inputsAreValid, - onClick = { - when (bundleType) { - BundleType.Local -> onLocalSubmit(patchBundle!!, integrations) - BundleType.Remote -> onRemoteSubmit(remoteUrl, autoUpdate) - } - }, - modifier = Modifier.padding(end = 16.dp) - ) { - Text(stringResource(R.string.import_)) - } - } - ) - }, - ) { paddingValues -> - BaseBundleDialog( - modifier = Modifier.padding(paddingValues), - isDefault = false, - name = null, - remoteUrl = remoteUrl.takeUnless { bundleType == BundleType.Local }, - onRemoteUrlChange = { remoteUrl = it }, - patchCount = 0, - version = null, - autoUpdate = autoUpdate, - onAutoUpdateChange = { autoUpdate = it }, - onPatchesClick = {}, - onBundleTypeClick = { - bundleType = when (bundleType) { - BundleType.Local -> BundleType.Remote - BundleType.Remote -> BundleType.Local - } - }, - ) { - if (bundleType == BundleType.Remote) return@BaseBundleDialog - - BundleListItem( - headlineText = stringResource(R.string.patch_bundle_field), - supportingText = stringResource(if (patchBundle != null) R.string.file_field_set else R.string.file_field_not_set), - trailingContent = { - IconButton( - onClick = ::launchPatchActivity - ) { - Icon( - imageVector = Icons.Default.Topic, - contentDescription = null - ) - } - }, - modifier = Modifier.clickable { - launchPatchActivity() - } - ) - - BundleListItem( - headlineText = stringResource(R.string.integrations_field), - supportingText = stringResource(if (integrations != null) R.string.file_field_set else R.string.file_field_not_set), - trailingContent = { - IconButton( - onClick = ::launchIntegrationsActivity - ) { - Icon( - imageVector = Icons.Default.Topic, - contentDescription = null - ) - } - }, - modifier = Modifier.clickable { - launchIntegrationsActivity() - } - ) + val steps = listOf<@Composable () -> Unit>( + { + SelectBundleTypeStep(bundleType) { selectedType -> + bundleType = selectedType } + }, + { + ImportBundleStep( + bundleType, + patchBundle, + integrations, + remoteUrl, + autoUpdate, + { launchPatchActivity() }, + { launchIntegrationsActivity() }, + { remoteUrl = it }, + { autoUpdate = it } + ) + } + ) + + val inputsAreValid by remember { + derivedStateOf { + (bundleType == BundleType.Local && patchBundle != null) || + (bundleType == BundleType.Remote && remoteUrl.isNotEmpty()) + } + } + + AlertDialogExtended( + onDismissRequest = onDismiss, + title = { + Text(stringResource(if (currentStep == 0) R.string.select else R.string.add_patch_bundle)) + }, + text = { + steps[currentStep]() + }, + confirmButton = { + if (currentStep == steps.lastIndex) { + TextButton( + enabled = inputsAreValid, + onClick = { + when (bundleType) { + BundleType.Local -> patchBundle?.let { + onLocalSubmit( + it, + integrations + ) + } + + BundleType.Remote -> onRemoteSubmit(remoteUrl, autoUpdate) + } + } + ) { + Text(stringResource(R.string.add)) + } + } else { + TextButton(onClick = { currentStep++ }) { + Text(stringResource(R.string.next)) + } + } + }, + dismissButton = { + if (currentStep > 0) { + TextButton(onClick = { currentStep-- }) { + Text(stringResource(R.string.back)) + } + } else { + TextButton(onClick = onDismiss) { + Text(stringResource(R.string.cancel)) + } + } + }, + textHorizontalPadding = PaddingValues(0.dp) + ) +} + +@Composable +fun SelectBundleTypeStep( + bundleType: BundleType, + onBundleTypeSelected: (BundleType) -> Unit +) { + Column( + verticalArrangement = Arrangement.spacedBy(24.dp) + ) { + Text( + modifier = Modifier.padding(horizontal = 24.dp), + text = stringResource(R.string.select_bundle_type_dialog_description) + ) + Column { + ListItem( + modifier = Modifier.clickable( + role = Role.RadioButton, + onClick = { onBundleTypeSelected(BundleType.Remote) } + ), + headlineContent = { Text(stringResource(R.string.enter_url)) }, + overlineContent = { Text(stringResource(R.string.recommended)) }, + supportingContent = { Text(stringResource(R.string.remote_bundle_description)) }, + leadingContent = { + RadioButton( + selected = bundleType == BundleType.Remote, + onClick = null + ) + } + ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp)) + ListItem( + modifier = Modifier.clickable( + role = Role.RadioButton, + onClick = { onBundleTypeSelected(BundleType.Local) } + ), + headlineContent = { Text(stringResource(R.string.select_from_storage)) }, + supportingContent = { Text(stringResource(R.string.local_bundle_description)) }, + overlineContent = { }, + leadingContent = { + RadioButton( + selected = bundleType == BundleType.Local, + onClick = null + ) + } + ) } } } + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ImportBundleStep( + bundleType: BundleType, + patchBundle: Uri?, + integrations: Uri?, + remoteUrl: String, + autoUpdate: Boolean, + launchPatchActivity: () -> Unit, + launchIntegrationsActivity: () -> Unit, + onRemoteUrlChange: (String) -> Unit, + onAutoUpdateChange: (Boolean) -> Unit +) { + Column { + when (bundleType) { + BundleType.Local -> { + Column( + modifier = Modifier.padding(horizontal = 8.dp) + ) { + ListItem( + headlineContent = { + 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 = { + IconButton(onClick = launchPatchActivity) { + Icon(imageVector = Icons.Default.Topic, contentDescription = null) + } + }, + modifier = Modifier.clickable { launchPatchActivity() } + ) + ListItem( + headlineContent = { + Text(stringResource(R.string.integrations_field)) + }, + supportingContent = { Text(stringResource(if (integrations != null) R.string.file_field_set else R.string.file_field_not_set)) }, + trailingContent = { + IconButton(onClick = launchIntegrationsActivity) { + Icon(imageVector = Icons.Default.Topic, contentDescription = null) + } + }, + modifier = Modifier.clickable { launchIntegrationsActivity() } + ) + } + } + + BundleType.Remote -> { + Column( + modifier = Modifier.padding(TextHorizontalPadding) + ) { + OutlinedTextField( + value = remoteUrl, + onValueChange = onRemoteUrlChange, + label = { Text(stringResource(R.string.bundle_url)) } + ) + } + Column( + modifier = Modifier.padding(horizontal = 8.dp) + ) { + ListItem( + modifier = Modifier.clickable( + role = Role.Checkbox, + onClick = { onAutoUpdateChange(!autoUpdate) } + ), + headlineContent = { Text(stringResource(R.string.auto_update)) }, + leadingContent = { + CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) { + Checkbox( + checked = autoUpdate, + onCheckedChange = { + onAutoUpdateChange(!autoUpdate) + } + ) + } + }, + ) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleTypeSelectorDialog.kt b/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleTypeSelectorDialog.kt deleted file mode 100644 index b3f32ad9..00000000 --- a/app/src/main/java/app/revanced/manager/ui/component/bundle/ImportBundleTypeSelectorDialog.kt +++ /dev/null @@ -1,95 +0,0 @@ -package app.revanced.manager.ui.component.bundle - -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.ListItem -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.Role -import androidx.compose.ui.unit.dp -import app.revanced.manager.R -import app.revanced.manager.ui.component.AlertDialogExtended -import app.revanced.manager.ui.model.BundleType - -@Composable -fun ImportBundleTypeSelectorDialog( - onDismiss: () -> Unit, - onConfirm: (BundleType) -> Unit, -) { - var bundleType: BundleType by rememberSaveable { mutableStateOf(BundleType.Remote) } - - AlertDialogExtended( - onDismissRequest = onDismiss, - confirmButton = { - TextButton( - onClick = { onConfirm(bundleType) } - ) { - Text(stringResource(R.string.select)) - } - }, - dismissButton = { - TextButton(onClick = onDismiss) { - Text(stringResource(R.string.cancel)) - } - }, - title = { - Text(stringResource(R.string.select_bundle_type_dialog_title)) - }, - text = { - Column( - verticalArrangement = Arrangement.spacedBy(24.dp) - ) { - Text( - modifier = Modifier.padding(horizontal = 24.dp), - text = stringResource(R.string.select_bundle_type_dialog_description) - ) - Column { - ListItem( - modifier = Modifier.clickable( - role = Role.RadioButton, - onClick = { bundleType = BundleType.Remote } - ), - headlineContent = { Text(stringResource(R.string.remote)) }, - overlineContent = { Text(stringResource(R.string.recommended)) }, - supportingContent = { Text(stringResource(R.string.remote_bundle_description)) }, - leadingContent = { - RadioButton( - selected = bundleType == BundleType.Remote, - onClick = null - ) - } - ) - HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp)) - ListItem( - modifier = Modifier.clickable( - role = Role.RadioButton, - onClick = { bundleType = BundleType.Local } - ), - headlineContent = { Text(stringResource(R.string.local)) }, - supportingContent = { Text(stringResource(R.string.local_bundle_description)) }, - overlineContent = { }, // we're using this parameter to force the 3-line ListItem state - leadingContent = { - RadioButton( - selected = bundleType == BundleType.Local, - onClick = null - ) - } - ) - } - } - }, - textHorizontalPadding = PaddingValues(0.dp) - ) -} diff --git a/app/src/main/java/app/revanced/manager/ui/component/settings/Changelog.kt b/app/src/main/java/app/revanced/manager/ui/component/settings/Changelog.kt index 0a609e78..6e707ae2 100644 --- a/app/src/main/java/app/revanced/manager/ui/component/settings/Changelog.kt +++ b/app/src/main/java/app/revanced/manager/ui/component/settings/Changelog.kt @@ -55,10 +55,6 @@ fun Changelog( modifier = Modifier .fillMaxWidth() ) { - Tag( - Icons.Outlined.Sell, - version - ) Tag( Icons.Outlined.FileDownload, downloadCount diff --git a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt index 288bc0e1..11681824 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/DashboardScreen.kt @@ -58,9 +58,7 @@ import app.revanced.manager.ui.component.AutoUpdatesDialog import app.revanced.manager.ui.component.NotificationCard import app.revanced.manager.ui.component.bundle.BundleItem import app.revanced.manager.ui.component.bundle.BundleTopBar -import app.revanced.manager.ui.component.bundle.ImportBundleDialog -import app.revanced.manager.ui.component.bundle.ImportBundleTypeSelectorDialog -import app.revanced.manager.ui.model.BundleType +import app.revanced.manager.ui.component.bundle.ImportPatchBundleDialog import app.revanced.manager.ui.viewmodel.DashboardViewModel import app.revanced.manager.util.toast import kotlinx.coroutines.launch @@ -100,33 +98,17 @@ fun DashboardScreen( val firstLaunch by vm.prefs.firstLaunch.getAsState() if (firstLaunch) AutoUpdatesDialog(vm::applyAutoUpdatePrefs) - var selectedBundleType: BundleType? by rememberSaveable { mutableStateOf(null) } - selectedBundleType?.let { - fun dismiss() { - selectedBundleType = null - } - - ImportBundleDialog( - onDismissRequest = ::dismiss, + var showAddBundleDialog by rememberSaveable { mutableStateOf(false) } + if (showAddBundleDialog) { + ImportPatchBundleDialog( + onDismiss = { showAddBundleDialog = false }, onLocalSubmit = { patches, integrations -> - dismiss() + showAddBundleDialog = false vm.createLocalSource(patches, integrations) }, onRemoteSubmit = { url, autoUpdate -> - dismiss() + showAddBundleDialog = false vm.createRemoteSource(url, autoUpdate) - }, - initialBundleType = it - ) - } - - var showBundleTypeSelectorDialog by rememberSaveable { mutableStateOf(false) } - if (showBundleTypeSelectorDialog) { - ImportBundleTypeSelectorDialog( - onDismiss = { showBundleTypeSelectorDialog = false }, - onConfirm = { - selectedBundleType = it - showBundleTypeSelectorDialog = false } ) } @@ -200,7 +182,7 @@ fun DashboardScreen( } DashboardPage.BUNDLES.ordinal -> { - showBundleTypeSelectorDialog = true + showAddBundleDialog = true } } } @@ -238,7 +220,6 @@ fun DashboardScreen( if (vm.showBatteryOptimizationsWarning) { { NotificationCard( - modifier = Modifier.padding(16.dp), isWarning = true, icon = Icons.Default.BatteryAlert, text = stringResource(R.string.battery_optimization_notification), @@ -260,7 +241,7 @@ fun DashboardScreen( Text(stringResource(R.string.dismiss)) } TextButton(onClick = onUpdateClick) { - Text(stringResource(R.string.update)) + Text(stringResource(R.string.show)) } } ) diff --git a/app/src/main/java/app/revanced/manager/ui/screen/SelectedAppInfoScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/SelectedAppInfoScreen.kt index f38aa457..0dd786d7 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/SelectedAppInfoScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/SelectedAppInfoScreen.kt @@ -3,12 +3,13 @@ package app.revanced.manager.ui.screen import android.content.pm.PackageInfo import androidx.annotation.StringRes import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.outlined.ArrowRight +import androidx.compose.material.icons.filled.AutoFixHigh import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.ListItem import androidx.compose.material3.MaterialTheme @@ -26,6 +27,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import app.revanced.manager.R import app.revanced.manager.ui.component.AppInfo import app.revanced.manager.ui.component.AppTopBar +import app.revanced.manager.ui.component.ColumnWithScrollbar import app.revanced.manager.ui.destination.SelectedAppInfoDestination import app.revanced.manager.ui.model.BundleInfo.Extensions.bundleInfoFlow import app.revanced.manager.ui.model.SelectedApp @@ -164,9 +166,16 @@ private fun SelectedAppInfoScreen( title = stringResource(R.string.app_info), onBackClick = onBackClick ) + }, + floatingActionButton = { + ExtendedFloatingActionButton( + text = { Text(stringResource(R.string.patch)) }, + icon = { Icon(Icons.Default.AutoFixHigh, null) }, + onClick = onPatchClick + ) } ) { paddingValues -> - Column( + ColumnWithScrollbar( modifier = Modifier .fillMaxSize() .padding(paddingValues) @@ -179,15 +188,6 @@ private fun SelectedAppInfoScreen( ) } - PageItem(R.string.patch, stringResource(R.string.patch_item_description), onPatchClick) - - Text( - stringResource(R.string.advanced), - color = MaterialTheme.colorScheme.primary, - style = MaterialTheme.typography.labelLarge, - modifier = Modifier.padding(horizontal = 24.dp, vertical = 8.dp) - ) - PageItem( R.string.patch_selector_item, stringResource(R.string.patch_selector_item_description, selectedPatchCount), diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt index e596ea3e..997d5284 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/AdvancedSettingsScreen.kt @@ -10,7 +10,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Http +import androidx.compose.material.icons.outlined.Api import androidx.compose.material3.AlertDialog import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -32,6 +32,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.core.content.getSystemService import androidx.lifecycle.viewModelScope +import app.revanced.manager.BuildConfig import app.revanced.manager.R import app.revanced.manager.ui.component.AppTopBar import app.revanced.manager.ui.component.ColumnWithScrollbar @@ -145,22 +146,17 @@ fun AdvancedSettingsScreen( description = R.string.patch_selection_safeguard_description ) - GroupHeader(stringResource(R.string.device)) + GroupHeader(stringResource(R.string.debugging)) SettingsListItem( - headlineContent = stringResource(R.string.device_model), - supportingContent = Build.MODEL - ) - SettingsListItem( - headlineContent = stringResource(R.string.device_android_version), - supportingContent = Build.VERSION.RELEASE - ) - SettingsListItem( - headlineContent = stringResource(R.string.device_architectures), - supportingContent = Build.SUPPORTED_ABIS.joinToString(", ") - ) - SettingsListItem( - headlineContent = stringResource(R.string.device_memory_limit), - supportingContent = memoryLimit + headlineContent = stringResource(R.string.about_device), + supportingContent = """ + **Version**: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}) + **Build type**: ${BuildConfig.BUILD_TYPE} + **Model**: ${Build.MODEL} + **Android version**: ${Build.VERSION.RELEASE} (${Build.VERSION.SDK_INT}) + **Supported Archs**: ${Build.SUPPORTED_ABIS.joinToString(", ")} + **Memory limit**: $memoryLimit + """.trimIndent() ) } } @@ -187,7 +183,7 @@ private fun APIUrlDialog(currentUrl: String, onSubmit: (String?) -> Unit) { } }, icon = { - Icon(Icons.Outlined.Http, null) + Icon(Icons.Outlined.Api, null) }, title = { Text( diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/GeneralSettingsScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/GeneralSettingsScreen.kt index 4fb32ea7..f41e6a66 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/GeneralSettingsScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/GeneralSettingsScreen.kt @@ -112,7 +112,7 @@ private fun ThemePicker( } }, confirmButton = { - Button( + TextButton( onClick = { onConfirm(selectedTheme) onDismiss() diff --git a/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdateScreen.kt b/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdateScreen.kt index cb1639f4..4b41dbd9 100644 --- a/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdateScreen.kt +++ b/app/src/main/java/app/revanced/manager/ui/screen/settings/update/UpdateScreen.kt @@ -56,7 +56,7 @@ fun UpdateScreen( Scaffold( topBar = { AppTopBar( - title = stringResource(R.string.updates), + title = stringResource(R.string.update), onBackClick = onBackClick ) } diff --git a/app/src/main/java/app/revanced/manager/util/Util.kt b/app/src/main/java/app/revanced/manager/util/Util.kt index 56dfc4ae..f1de38fd 100644 --- a/app/src/main/java/app/revanced/manager/util/Util.kt +++ b/app/src/main/java/app/revanced/manager/util/Util.kt @@ -11,6 +11,7 @@ import android.os.Build import android.util.Log import android.widget.Toast import androidx.annotation.StringRes +import androidx.compose.foundation.ScrollState import androidx.compose.foundation.lazy.LazyListState import androidx.compose.runtime.Composable import androidx.compose.runtime.State @@ -175,6 +176,9 @@ fun String.relativeTime(context: Context): String { } } + +const val isScrollingUpSensitivity = 10 + @Composable fun LazyListState.isScrollingUp(): State { return remember(this) { @@ -182,10 +186,16 @@ fun LazyListState.isScrollingUp(): State { var previousScrollOffset by mutableIntStateOf(firstVisibleItemScrollOffset) derivedStateOf { - if (previousIndex != firstVisibleItemIndex) { + val indexChanged = previousIndex != firstVisibleItemIndex + val offsetChanged = + kotlin.math.abs(previousScrollOffset - firstVisibleItemScrollOffset) > isScrollingUpSensitivity + + if (indexChanged) { previousIndex > firstVisibleItemIndex + } else if (offsetChanged) { + previousScrollOffset > firstVisibleItemScrollOffset } else { - previousScrollOffset >= firstVisibleItemScrollOffset + true }.also { previousIndex = firstVisibleItemIndex previousScrollOffset = firstVisibleItemScrollOffset @@ -194,4 +204,18 @@ fun LazyListState.isScrollingUp(): State { } } -val LazyListState.isScrollingUp: Boolean @Composable get() = this.isScrollingUp().value \ No newline at end of file +// TODO: support sensitivity +@Composable +fun ScrollState.isScrollingUp(): State { + return remember(this) { + var previousScrollOffset by mutableIntStateOf(value) + derivedStateOf { + (previousScrollOffset >= value).also { + previousScrollOffset = value + } + } + } +} + +val LazyListState.isScrollingUp: Boolean @Composable get() = this.isScrollingUp().value +val ScrollState.isScrollingUp: Boolean @Composable get() = this.isScrollingUp().value \ No newline at end of file diff --git a/app/src/main/jniLibs/armeabi-v7a/libaapt2.so b/app/src/main/jniLibs/armeabi-v7a/libaapt2.so deleted file mode 100644 index 8506316d..00000000 Binary files a/app/src/main/jniLibs/armeabi-v7a/libaapt2.so and /dev/null differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1619bb64..f6c8d3c5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -18,8 +18,8 @@ Bundle patches Patch bundle Integrations - Provided - Not provided + Selected + Not selected Not set @@ -42,8 +42,8 @@ Could not import legacy settings - Select updates to receive - Periodically connect to update providers to check for updates. + Configure updates + Do you want ReVanced Manager to periodically check for updates for the following components? ReVanced Manager ReVanced Patches These settings can be changed later. @@ -169,7 +169,7 @@ Model CPU Architectures Memory limits - Normal: %1$d MB, Large: %2$d MB + %1$dMB (Normal) - %2$dMB (Large) Patch bundles Redownload all patch bundles Reset patch bundles @@ -363,9 +363,17 @@ No contributors found Select Select or deselect all - Select bundle type - Select the type that is right for you. + Add new bundle + Add a new bundle from a URL or storage Import local files from your storage, does not automatically update Import remote files from a URL, can automatically update Recommended + Show + Debugging + About device + Enter URL + Next + Add patch bundle + Bundle URL + Auto update diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d8dd4f25..6b956b85 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,4 @@ [versions] -kotlin = "1.9.22" ktx = "1.13.1" material3 = "1.3.0-beta04" ui-tooling = "1.6.8" @@ -24,9 +23,10 @@ reimagined-navigation = "1.5.0" ktor = "2.3.9" markdown-renderer = "0.22.0" fading-edges = "1.0.4" -androidGradlePlugin = "8.3.2" -devToolsGradlePlugin = "1.9.22-1.0.17" -aboutLibrariesGradlePlugin = "11.1.1" +android-gradle-plugin = "8.3.2" +kotlin-gradle-plugin = "1.9.22" +dev-tools-gradle-plugin = "1.9.22-1.0.17" +about-libraries-gradle-plugin = "11.1.1" binary-compatibility-validator = "0.15.1" coil = "2.6.0" app-icon-loader-coil = "1.5.0" @@ -89,8 +89,8 @@ koin-workmanager = { group = "io.insert-koin", name = "koin-androidx-workmanager # Compose Navigation reimagined-navigation = { group = "dev.olshevski.navigation", name = "reimagined", version.ref = "reimagined-navigation" } -# about-libraries -about-libraries = { group = "com.mikepenz", name = "aboutlibraries-compose", version.ref = "aboutLibrariesGradlePlugin" } +# About Libraries +about-libraries = { group = "com.mikepenz", name = "aboutlibraries-compose", version.ref = "about-libraries-gradle-plugin" } # Ktor ktor-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" } @@ -131,9 +131,9 @@ reorderable = { module = "sh.calvin.reorderable:reorderable", version.ref = "reo compose-icons-fontawesome = { group = "com.github.BenjaminHalko.compose-icons", name = "font-awesome", version.ref = "compose-icons" } [plugins] -android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } -kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } -devtools = { id = "com.google.devtools.ksp", version.ref = "devToolsGradlePlugin" } -about-libraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutLibrariesGradlePlugin" } -android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } +android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } +android-library = { id = "com.android.library", version.ref = "android-gradle-plugin" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin-gradle-plugin" } +devtools = { id = "com.google.devtools.ksp", version.ref = "dev-tools-gradle-plugin" } +about-libraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "about-libraries-gradle-plugin" } binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" } \ No newline at end of file