mirror of
https://github.com/revanced/revanced-manager.git
synced 2025-05-03 15:24:25 +02:00
Merge branch 'compose-dev' into compose/downloader-system
This commit is contained in:
commit
9ddd421b2a
4
.github/workflows/pr-build.yml
vendored
4
.github/workflows/pr-build.yml
vendored
@ -24,7 +24,7 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
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
|
||||
|
4
.github/workflows/release-build.yml
vendored
4
.github/workflows/release-build.yml
vendored
@ -21,9 +21,7 @@ jobs:
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Set up Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
with:
|
||||
cache-disabled: true
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
|
||||
- name: Build with Gradle
|
||||
env:
|
||||
|
2
.github/workflows/update-documentation.yml
vendored
2
.github/workflows/update-documentation.yml
vendored
@ -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
|
||||
|
@ -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(
|
||||
@ -148,3 +148,5 @@ private fun ContentStyle(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val TextHorizontalPadding = PaddingValues(horizontal = 24.dp)
|
@ -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),
|
||||
|
@ -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<Uri?>(null) }
|
||||
var integrations by rememberSaveable { mutableStateOf<Uri?>(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)
|
||||
)
|
||||
val steps = listOf<@Composable () -> Unit>(
|
||||
{
|
||||
SelectBundleTypeStep(bundleType) { selectedType ->
|
||||
bundleType = selectedType
|
||||
}
|
||||
},
|
||||
actions = {
|
||||
{
|
||||
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 -> onLocalSubmit(patchBundle!!, integrations)
|
||||
BundleType.Local -> patchBundle?.let {
|
||||
onLocalSubmit(
|
||||
it,
|
||||
integrations
|
||||
)
|
||||
}
|
||||
|
||||
BundleType.Remote -> onRemoteSubmit(remoteUrl, autoUpdate)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(end = 16.dp)
|
||||
}
|
||||
) {
|
||||
Text(stringResource(R.string.import_))
|
||||
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)
|
||||
)
|
||||
},
|
||||
) { 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
|
||||
@Composable
|
||||
fun SelectBundleTypeStep(
|
||||
bundleType: BundleType,
|
||||
onBundleTypeSelected: (BundleType) -> Unit
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Topic,
|
||||
contentDescription = null
|
||||
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
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.clickable {
|
||||
launchPatchActivity()
|
||||
)
|
||||
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
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@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
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Topic,
|
||||
contentDescription = null
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.clickable {
|
||||
launchIntegrationsActivity()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
)
|
||||
}
|
@ -55,10 +55,6 @@ fun Changelog(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Tag(
|
||||
Icons.Outlined.Sell,
|
||||
version
|
||||
)
|
||||
Tag(
|
||||
Icons.Outlined.FileDownload,
|
||||
downloadCount
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -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),
|
||||
|
@ -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(
|
||||
|
@ -112,7 +112,7 @@ private fun ThemePicker(
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
Button(
|
||||
TextButton(
|
||||
onClick = {
|
||||
onConfirm(selectedTheme)
|
||||
onDismiss()
|
||||
|
@ -56,7 +56,7 @@ fun UpdateScreen(
|
||||
Scaffold(
|
||||
topBar = {
|
||||
AppTopBar(
|
||||
title = stringResource(R.string.updates),
|
||||
title = stringResource(R.string.update),
|
||||
onBackClick = onBackClick
|
||||
)
|
||||
}
|
||||
|
@ -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<Boolean> {
|
||||
return remember(this) {
|
||||
@ -182,10 +186,16 @@ fun LazyListState.isScrollingUp(): State<Boolean> {
|
||||
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<Boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: support sensitivity
|
||||
@Composable
|
||||
fun ScrollState.isScrollingUp(): State<Boolean> {
|
||||
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
|
Binary file not shown.
@ -18,8 +18,8 @@
|
||||
<string name="bundle_patches">Bundle patches</string>
|
||||
<string name="patch_bundle_field">Patch bundle</string>
|
||||
<string name="integrations_field">Integrations</string>
|
||||
<string name="file_field_set">Provided</string>
|
||||
<string name="file_field_not_set">Not provided</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>
|
||||
|
||||
@ -42,8 +42,8 @@
|
||||
|
||||
<string name="legacy_import_failed">Could not import legacy settings</string>
|
||||
|
||||
<string name="auto_updates_dialog_title">Select updates to receive</string>
|
||||
<string name="auto_updates_dialog_description">Periodically connect to update providers to check for updates.</string>
|
||||
<string name="auto_updates_dialog_title">Configure updates</string>
|
||||
<string name="auto_updates_dialog_description">Do you want ReVanced Manager to periodically check for updates for the following components?</string>
|
||||
<string name="auto_updates_dialog_manager">ReVanced Manager</string>
|
||||
<string name="auto_updates_dialog_patches">ReVanced Patches</string>
|
||||
<string name="auto_updates_dialog_note">These settings can be changed later.</string>
|
||||
@ -169,7 +169,7 @@
|
||||
<string name="device_model">Model</string>
|
||||
<string name="device_architectures">CPU Architectures</string>
|
||||
<string name="device_memory_limit">Memory limits</string>
|
||||
<string name="device_memory_limit_format">Normal: %1$d MB, Large: %2$d MB</string>
|
||||
<string name="device_memory_limit_format">%1$dMB (Normal) - %2$dMB (Large)</string>
|
||||
<string name="patch_bundles_section">Patch bundles</string>
|
||||
<string name="patch_bundles_redownload">Redownload all patch bundles</string>
|
||||
<string name="patch_bundles_reset">Reset patch bundles</string>
|
||||
@ -363,9 +363,17 @@
|
||||
<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_bundle_type_dialog_title">Select bundle type</string>
|
||||
<string name="select_bundle_type_dialog_description">Select the type that is right for you.</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="show">Show</string>
|
||||
<string name="debugging">Debugging</string>
|
||||
<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>
|
||||
</resources>
|
||||
|
@ -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" }
|
Loading…
x
Reference in New Issue
Block a user