add string resources and fix webview bugs

This commit is contained in:
Ax333l 2024-12-19 20:17:56 +01:00
parent d0cd29d625
commit 829f093afe
No known key found for this signature in database
GPG Key ID: D2B4D85271127D23
9 changed files with 73 additions and 48 deletions

View File

@ -76,7 +76,7 @@ class PatcherWorker(
val logger: Logger,
val downloadProgress: MutableStateFlow<Pair<Double, Double?>?>,
val patchesProgress: MutableStateFlow<Pair<Int, Int>>,
val handleStartActivityRequest: suspend (Intent) -> ActivityResult,
val handleStartActivityRequest: suspend (LoadedDownloaderPlugin, Intent) -> ActivityResult,
val setInputFile: (File) -> Unit,
val onProgress: ProgressEventHandler
) {
@ -182,7 +182,7 @@ class PatcherWorker(
override val pluginPackageName = plugin.packageName
override val hostPackageName = applicationContext.packageName
override suspend fun requestStartActivity(intent: Intent): Intent? {
val result = args.handleStartActivityRequest(intent)
val result = args.handleStartActivityRequest(plugin, intent)
return when (result.resultCode) {
Activity.RESULT_OK -> result.data
Activity.RESULT_CANCELED -> throw UserInteractionException.Activity.Cancelled()

View File

@ -96,7 +96,7 @@ fun PatcherScreen(
activityLauncher.launch(intent)
}
if (vm.showActivityPromptDialog)
vm.activityPromptDialog?.let { title ->
AlertDialog(
onDismissRequest = vm::rejectInteraction,
confirmButton = {
@ -113,11 +113,12 @@ fun PatcherScreen(
Text(stringResource(R.string.cancel))
}
},
title = { Text("User interaction required.") },
title = { Text(title) },
text = {
Text("User interaction is required to proceed.")
Text(stringResource(R.string.plugin_activity_dialog_body))
}
)
}
AppScaffold(
topBar = {

View File

@ -273,7 +273,7 @@ private fun AppSourceSelectorDialog(
Text(stringResource(R.string.cancel))
}
},
title = { Text("Select source") },
title = { Text(stringResource(R.string.app_source_dialog_title)) },
textHorizontalPadding = PaddingValues(horizontal = 0.dp),
text = {
LazyColumn {
@ -283,8 +283,15 @@ private fun AppSourceSelectorDialog(
modifier = Modifier
.clickable(enabled = canSelect && hasPlugins) { onSelect(searchApp) }
.enabled(hasPlugins),
headlineContent = { Text("Auto") },
supportingContent = { Text(if (hasPlugins) "Use all installed downloaders to find a suitable app." else "No plugins available") },
headlineContent = { Text(stringResource(R.string.app_source_dialog_option_auto)) },
supportingContent = {
Text(
if (hasPlugins)
stringResource(R.string.app_source_dialog_option_auto_description)
else
stringResource(R.string.app_source_dialog_option_auto_unavailable)
)
},
colors = transparentListItemColors
)
}
@ -293,11 +300,17 @@ private fun AppSourceSelectorDialog(
item(key = "installed") {
val (usable, text) = when {
// Mounted apps must be unpatched before patching, which cannot be done without root access.
meta?.installType == InstallType.MOUNT && !hasRoot -> false to "Mounted apps cannot be patched again without root access"
meta?.installType == InstallType.MOUNT && !hasRoot -> false to stringResource(
R.string.app_source_dialog_option_installed_no_root
)
// Patching already patched apps is not allowed because patches expect unpatched apps.
meta?.installType == InstallType.DEFAULT -> false to stringResource(R.string.already_patched)
// Version does not match suggested version.
requiredVersion != null && app.version != requiredVersion -> false to "Version ${app.version} does not match the suggested version"
requiredVersion != null && app.version != requiredVersion -> false to stringResource(
R.string.app_source_dialog_option_installed_version_not_suggested,
app.version
)
else -> true to app.version
}
ListItem(
@ -315,7 +328,6 @@ private fun AppSourceSelectorDialog(
ListItem(
modifier = Modifier.clickable(enabled = canSelect) { onSelectPlugin(plugin) },
headlineContent = { Text(plugin.name) },
supportingContent = { Text("Try to find the app using ${plugin.name}") },
trailingContent = (@Composable { LoadingIndicator() }).takeIf { activeSearchJob == plugin.packageName },
colors = transparentListItemColors
)

View File

@ -98,8 +98,8 @@ class PatcherViewModel(
var isInstalling by mutableStateOf(false)
private set
private var currentActivityRequest: CompletableDeferred<Boolean>? by mutableStateOf(null)
val showActivityPromptDialog by derivedStateOf { currentActivityRequest != null }
private var currentActivityRequest: Pair<CompletableDeferred<Boolean>, String>? by mutableStateOf(null)
val activityPromptDialog by derivedStateOf { currentActivityRequest?.second }
private var launchedActivity: CompletableDeferred<ActivityResult>? = null
private val launchActivityChannel = Channel<Intent>()
@ -146,13 +146,13 @@ class PatcherViewModel(
downloadProgress,
patchesProgress,
setInputFile = { inputFile = it },
handleStartActivityRequest = { intent ->
handleStartActivityRequest = { plugin, intent ->
withContext(Dispatchers.Main) {
if (currentActivityRequest != null) throw Exception("Another request is already pending.")
try {
// Wait for the dialog interaction.
val accepted = with(CompletableDeferred<Boolean>()) {
currentActivityRequest = this
currentActivityRequest = this to plugin.name
await()
}
@ -291,11 +291,11 @@ class PatcherViewModel(
fun isDeviceRooted() = rootInstaller.isDeviceRooted()
fun rejectInteraction() {
currentActivityRequest?.complete(false)
currentActivityRequest?.first?.complete(false)
}
fun allowInteraction() {
currentActivityRequest?.complete(true)
currentActivityRequest?.first?.complete(true)
}
fun handleActivityResult(result: ActivityResult) {

View File

@ -36,6 +36,12 @@
<string name="bundle_name_fallback">Unnamed</string>
<string name="selected_app_meta_any_version">Any available version</string>
<string name="app_source_dialog_title">Select source</string>
<string name="app_source_dialog_option_auto">Auto</string>
<string name="app_source_dialog_option_auto_description">Use all installed downloaders to find a suitable APK file</string>
<string name="app_source_dialog_option_auto_unavailable">No plugins available</string>
<string name="app_source_dialog_option_installed_no_root">Mounted apps cannot be patched again without root access</string>
<string name="app_source_dialog_option_installed_version_not_suggested">Version %s does not match the suggested version</string>
<string name="patch_item_description">Start patching the application</string>
<string name="patch_selector_item">Patch selection and options</string>
@ -275,6 +281,7 @@
<string name="save_apk_success">APK Saved</string>
<string name="sign_fail">Failed to sign APK: %s</string>
<string name="save_logs">Save logs</string>
<string name="plugin_activity_dialog_body">User interaction is required in order to proceed with this plugin.</string>
<string name="select_install_type">Select installation type</string>
<string name="patcher_step_group_preparing">Preparing</string>

View File

@ -5,11 +5,13 @@ import android.os.Bundle
import android.os.IBinder
import android.os.Parcelable
import android.view.MenuItem
import android.view.MotionEvent
import android.webkit.CookieManager
import android.webkit.WebSettings
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.ComponentActivity
import androidx.activity.addCallback
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.core.view.ViewCompat
@ -31,14 +33,20 @@ class WebViewActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
val vm by viewModels<WebViewModel>()
enableEdgeToEdge()
setContentView(R.layout.activity_webview)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
val webView = findViewById<WebView>(R.id.webview)
onBackPressedDispatcher.addCallback {
if (webView.canGoBack()) webView.goBack()
else cancelActivity()
}
val params = intent.getParcelableExtra<Parameters>(KEY)!!
actionBar?.apply {
title = params.title
@ -49,12 +57,11 @@ class WebViewActivity : ComponentActivity() {
val events = IWebViewEvents.Stub.asInterface(params.events)!!
vm.setup(events)
val webView = findViewById<WebView>(R.id.content).apply {
webView.apply {
settings.apply {
cacheMode = WebSettings.LOAD_NO_CACHE
databaseEnabled = false
allowContentAccess = false
domStorageEnabled = false
domStorageEnabled = true
javaScriptEnabled = true
}
@ -80,9 +87,14 @@ class WebViewActivity : ComponentActivity() {
}
}
override fun onOptionsItemSelected(item: MenuItem) = if (item.itemId == android.R.id.home) {
private fun cancelActivity() {
setResult(RESULT_CANCELED)
finish()
}
override fun onOptionsItemSelected(item: MenuItem) = if (item.itemId == android.R.id.home) {
cancelActivity()
true
} else super.onOptionsItemSelected(item)

View File

@ -1,16 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".webview.WebViewActivity">
android:id="@+id/main">
<WebView
android:id="@+id/content"
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteX="1dp"
tools:layout_editor_absoluteY="1dp" />
android:layout_height="match_parent" />
</LinearLayout>

View File

@ -12,18 +12,6 @@ import app.revanced.manager.plugin.downloader.webview.WebViewDownloader
import kotlinx.parcelize.Parcelize
import kotlin.io.path.*
// TODO: update UI error presentation and strings
@Parcelize
class InstalledApp(val path: String) : Parcelable
private val application by lazy {
// Don't do this in a real plugin.
val clazz = Class.forName("android.app.ActivityThread")
val activityThread = clazz.getMethod("currentActivityThread")(null)
clazz.getMethod("getApplication")(activityThread) as Application
}
val apkMirrorDownloader = WebViewDownloader { packageName, version ->
with(Uri.Builder()) {
scheme("https")
@ -41,6 +29,16 @@ val apkMirrorDownloader = WebViewDownloader { packageName, version ->
}
}
@Parcelize
class InstalledApp(val path: String) : Parcelable
private val application by lazy {
// Don't do this in a real plugin.
val clazz = Class.forName("android.app.ActivityThread")
val activityThread = clazz.getMethod("currentActivityThread")(null)
clazz.getMethod("getApplication")(activityThread) as Application
}
val installedAppDownloader = Downloader<InstalledApp> {
val pm = application.packageManager
@ -68,4 +66,4 @@ val installedAppDownloader = Downloader<InstalledApp> {
reportSize(path.fileSize())
Files.copy(path, outputStream)
}*/
}
}

View File

@ -1,14 +1,14 @@
[versions]
ktx = "1.15.0"
material3 = "1.3.1"
ui-tooling = "1.7.5"
ui-tooling = "1.7.6"
viewmodel-lifecycle = "2.8.7"
splash-screen = "1.0.1"
activity = "1.9.3"
appcompat = "1.7.0"
preferences-datastore = "1.1.1"
work-runtime = "2.10.0"
compose-bom = "2024.11.00"
compose-bom = "2024.12.01"
accompanist = "0.34.0"
placeholder = "1.1.2"
reorderable = "1.5.2"
@ -24,9 +24,9 @@ reimagined-navigation = "1.5.0"
ktor = "2.3.9"
markdown-renderer = "0.22.0"
fading-edges = "1.0.4"
kotlin = "2.0.21"
android-gradle-plugin = "8.7.2"
dev-tools-gradle-plugin = "2.0.21-1.0.27"
kotlin = "2.1.0"
android-gradle-plugin = "8.7.3"
dev-tools-gradle-plugin = "2.1.0-1.0.29"
about-libraries-gradle-plugin = "11.1.1"
binary-compatibility-validator = "0.15.1"
coil = "2.6.0"