mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2024-11-10 01:01:56 +01:00
parent
495100dea9
commit
1bf004ddee
5 changed files with 240 additions and 243 deletions
|
@ -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)
|
|
@ -4,166 +4,269 @@ 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, String, Boolean) -> Unit,
|
||||
onLocalSubmit: (String, Uri, Uri?) -> Unit,
|
||||
initialBundleType: BundleType
|
||||
onLocalSubmit: (String, Uri, Uri?) -> Unit
|
||||
) {
|
||||
var name by rememberSaveable { mutableStateOf("") }
|
||||
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 {
|
||||
name.isNotEmpty() && 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 ->
|
||||
uri?.let { patchBundle = it }
|
||||
}
|
||||
fun launchPatchActivity() {
|
||||
patchActivityLauncher.launch(JAR_MIMETYPE)
|
||||
}
|
||||
|
||||
val integrationsActivityLauncher =
|
||||
rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
uri?.let { integrations = it }
|
||||
}
|
||||
fun launchIntegrationsActivity() {
|
||||
integrationsActivityLauncher.launch(APK_MIMETYPE)
|
||||
|
||||
val steps = listOf<@Composable () -> Unit>(
|
||||
{
|
||||
SelectBundleTypeStep(bundleType) { selectedType ->
|
||||
bundleType = selectedType
|
||||
}
|
||||
},
|
||||
{
|
||||
ImportBundleStep(
|
||||
bundleType,
|
||||
patchBundle,
|
||||
integrations,
|
||||
remoteUrl,
|
||||
autoUpdate,
|
||||
{ patchActivityLauncher.launch(JAR_MIMETYPE) },
|
||||
{ integrationsActivityLauncher.launch(APK_MIMETYPE) },
|
||||
{ remoteUrl = it },
|
||||
{ autoUpdate = it }
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val inputsAreValid by remember {
|
||||
derivedStateOf {
|
||||
(bundleType == BundleType.Local && patchBundle != null) ||
|
||||
(bundleType == BundleType.Remote && remoteUrl.isNotEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
Dialog(
|
||||
onDismissRequest = onDismissRequest,
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnBackPress = true
|
||||
)
|
||||
) {
|
||||
Scaffold(
|
||||
topBar = {
|
||||
BundleTopBar(
|
||||
title = stringResource(R.string.import_bundle),
|
||||
onBackClick = onDismissRequest,
|
||||
onBackIcon = {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Close,
|
||||
contentDescription = stringResource(R.string.close)
|
||||
)
|
||||
AlertDialogExtended(
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(stringResource(if (currentStep == 0) R.string.select else R.string.add_patch_bundle))
|
||||
},
|
||||
actions = {
|
||||
text = {
|
||||
steps[currentStep]()
|
||||
},
|
||||
confirmButton = {
|
||||
if (currentStep == steps.size - 1) {
|
||||
TextButton(
|
||||
enabled = inputsAreValid,
|
||||
onClick = {
|
||||
when (bundleType) {
|
||||
BundleType.Local -> onLocalSubmit(
|
||||
name,
|
||||
patchBundle!!,
|
||||
BundleType.Local -> patchBundle?.let {
|
||||
onLocalSubmit(
|
||||
"BundleName",
|
||||
it,
|
||||
integrations
|
||||
)
|
||||
BundleType.Remote -> onRemoteSubmit(name, remoteUrl, autoUpdate)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(end = 16.dp)
|
||||
) {
|
||||
Text(stringResource(R.string.import_))
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
) { paddingValues ->
|
||||
BaseBundleDialog(
|
||||
modifier = Modifier.padding(paddingValues),
|
||||
isDefault = false,
|
||||
name = name,
|
||||
onNameChange = { name = it },
|
||||
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
|
||||
BundleType.Remote -> onRemoteSubmit("BundleName", remoteUrl, autoUpdate)
|
||||
}
|
||||
}
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Topic,
|
||||
contentDescription = null
|
||||
)
|
||||
Text(stringResource(R.string.add))
|
||||
}
|
||||
} else {
|
||||
TextButton(onClick = { currentStep++ }) {
|
||||
Text(stringResource(R.string.next))
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = Modifier.clickable {
|
||||
launchPatchActivity()
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
@Composable
|
||||
fun SelectBundleTypeStep(
|
||||
bundleType: BundleType,
|
||||
onBundleTypeSelected: (BundleType) -> Unit
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(24.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Topic,
|
||||
contentDescription = null
|
||||
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)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
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)
|
||||
)
|
||||
}
|
|
@ -53,9 +53,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
|
||||
|
@ -94,33 +92,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 = { name, patches, integrations ->
|
||||
dismiss()
|
||||
showAddBundleDialog = false
|
||||
vm.createLocalSource(name, patches, integrations)
|
||||
},
|
||||
onRemoteSubmit = { name, url, autoUpdate ->
|
||||
dismiss()
|
||||
showAddBundleDialog = false
|
||||
vm.createRemoteSource(name, url, autoUpdate)
|
||||
},
|
||||
initialBundleType = it
|
||||
)
|
||||
}
|
||||
|
||||
var showBundleTypeSelectorDialog by rememberSaveable { mutableStateOf(false) }
|
||||
if (showBundleTypeSelectorDialog) {
|
||||
ImportBundleTypeSelectorDialog(
|
||||
onDismiss = { showBundleTypeSelectorDialog = false },
|
||||
onConfirm = {
|
||||
selectedBundleType = it
|
||||
showBundleTypeSelectorDialog = false
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -194,7 +176,7 @@ fun DashboardScreen(
|
|||
}
|
||||
|
||||
DashboardPage.BUNDLES.ordinal -> {
|
||||
showBundleTypeSelectorDialog = true
|
||||
showAddBundleDialog = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
@ -331,12 +331,17 @@
|
|||
<string name="download_update_confirmation">Download update?</string>
|
||||
<string name="no_contributors_found">No contributors found</string>
|
||||
<string name="select">Select</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>
|
||||
|
|
Loading…
Reference in a new issue