From 472614435c4f8673435cfc64d6d67c84f0ec37b5 Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Sun, 13 Oct 2024 21:26:49 +1300 Subject: [PATCH 1/6] Confirm Removal of Ext Installed via Private Installer --- .../presentation/browse/ExtensionsScreen.kt | 66 ++++++++++++++++++- .../moko-resources/base/strings.xml | 3 + 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt index 475f0172d5..c19c86b280 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -1,5 +1,6 @@ package eu.kanade.presentation.browse +import android.content.Context import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable @@ -55,6 +56,7 @@ import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.ui.browse.extension.ExtensionUiModel import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreenModel import eu.kanade.tachiyomi.util.system.LocaleHelper +import eu.kanade.tachiyomi.util.system.isPackageInstalled import eu.kanade.tachiyomi.util.system.launchRequestPackageInstallsPermission import kotlinx.collections.immutable.persistentListOf import tachiyomi.i18n.MR @@ -248,6 +250,7 @@ private fun ExtensionContent( } } }, + context = context, ) } } @@ -278,16 +281,47 @@ private fun ExtensionItem( onClickItemAction: (Extension) -> Unit, onClickItemSecondaryAction: (Extension) -> Unit, modifier: Modifier = Modifier, + context: Context, ) { val (extension, installStep) = item + var showUninstallConfirmation by remember { mutableStateOf(false) } + + if (showUninstallConfirmation) { + ExtensionUninstallConfirmation( + extensionName = extension.name, + onClickConfirm = { + onLongClickItem(extension) + showUninstallConfirmation = false + }, + onClickDismiss = { + showUninstallConfirmation = false + }, + onDismissRequest = { + showUninstallConfirmation = false + }, + ) + } + BaseBrowseItem( modifier = modifier .combinedClickable( onClick = { onClickItem(extension) }, - onLongClick = { onLongClickItem(extension) }, + onLongClick = { + if (context.isPackageInstalled(extension.pkgName)) { + onLongClickItem(extension) + } else { + showUninstallConfirmation = true + } + }, ), onClickItem = { onClickItem(extension) }, - onLongClickItem = { onLongClickItem(extension) }, + onLongClickItem = { + if (context.isPackageInstalled(extension.pkgName)) { + onLongClickItem(extension) + } else { + showUninstallConfirmation = true + } + }, icon = { Box( modifier = Modifier @@ -540,3 +574,31 @@ private fun ExtensionTrustDialog( onDismissRequest = onDismissRequest, ) } + +@Composable +private fun ExtensionUninstallConfirmation( + extensionName: String, + onClickConfirm: () -> Unit, + onClickDismiss: () -> Unit, + onDismissRequest: () -> Unit, +) { + AlertDialog( + title = { + Text(text = stringResource(MR.strings.ext_confirm_remove)) + }, + text = { + Text(text = stringResource(MR.strings.remove_private_extension_message, extensionName)) + }, + confirmButton = { + TextButton(onClick = onClickConfirm) { + Text(text = stringResource(MR.strings.ext_remove)) + } + }, + dismissButton = { + TextButton(onClick = onClickDismiss) { + Text(text = stringResource(MR.strings.action_cancel)) + } + }, + onDismissRequest = onDismissRequest, + ) +} diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index da39f34b1c..263f344453 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -325,10 +325,13 @@ Trust Untrusted Uninstall + Remove + Remove Extension? App info Untrusted extension Malicious extensions can read any stored login credentials or execute arbitrary code.\n\nBy trusting this extension, you accept these risks. This extension is no longer available. It may not function properly and can cause issues with the app. Uninstalling it is recommended. + Do you really want to remove the \"%s\" extension? Failed to fetch available extensions Version Language From 08f86fd92fff5fbb3e5bcd7a3ea7327e6cf97192 Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Sun, 13 Oct 2024 22:28:47 +1300 Subject: [PATCH 2/6] Lambda --- .../presentation/browse/ExtensionsScreen.kt | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt index c19c86b280..12d19a3c23 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -286,6 +286,14 @@ private fun ExtensionItem( val (extension, installStep) = item var showUninstallConfirmation by remember { mutableStateOf(false) } + val internalOnLongClickItem: () -> Unit = { + if (context.isPackageInstalled(extension.pkgName)) { + onLongClickItem(extension) + } else { + showUninstallConfirmation = true + } + } + if (showUninstallConfirmation) { ExtensionUninstallConfirmation( extensionName = extension.name, @@ -306,22 +314,10 @@ private fun ExtensionItem( modifier = modifier .combinedClickable( onClick = { onClickItem(extension) }, - onLongClick = { - if (context.isPackageInstalled(extension.pkgName)) { - onLongClickItem(extension) - } else { - showUninstallConfirmation = true - } - }, + onLongClick = internalOnLongClickItem, ), onClickItem = { onClickItem(extension) }, - onLongClickItem = { - if (context.isPackageInstalled(extension.pkgName)) { - onLongClickItem(extension) - } else { - showUninstallConfirmation = true - } - }, + onLongClickItem = internalOnLongClickItem, icon = { Box( modifier = Modifier From 645e30649fc7c1d1888b77986a14a3a4ba869c23 Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Sun, 13 Oct 2024 23:35:36 +1300 Subject: [PATCH 3/6] Move to `ExtensionTab` --- .../presentation/browse/ExtensionsScreen.kt | 62 +------------------ .../ui/browse/extension/ExtensionsTab.kt | 61 +++++++++++++++++- 2 files changed, 62 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt index 12d19a3c23..475f0172d5 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -1,6 +1,5 @@ package eu.kanade.presentation.browse -import android.content.Context import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable @@ -56,7 +55,6 @@ import eu.kanade.tachiyomi.extension.model.InstallStep import eu.kanade.tachiyomi.ui.browse.extension.ExtensionUiModel import eu.kanade.tachiyomi.ui.browse.extension.ExtensionsScreenModel import eu.kanade.tachiyomi.util.system.LocaleHelper -import eu.kanade.tachiyomi.util.system.isPackageInstalled import eu.kanade.tachiyomi.util.system.launchRequestPackageInstallsPermission import kotlinx.collections.immutable.persistentListOf import tachiyomi.i18n.MR @@ -250,7 +248,6 @@ private fun ExtensionContent( } } }, - context = context, ) } } @@ -281,43 +278,16 @@ private fun ExtensionItem( onClickItemAction: (Extension) -> Unit, onClickItemSecondaryAction: (Extension) -> Unit, modifier: Modifier = Modifier, - context: Context, ) { val (extension, installStep) = item - var showUninstallConfirmation by remember { mutableStateOf(false) } - - val internalOnLongClickItem: () -> Unit = { - if (context.isPackageInstalled(extension.pkgName)) { - onLongClickItem(extension) - } else { - showUninstallConfirmation = true - } - } - - if (showUninstallConfirmation) { - ExtensionUninstallConfirmation( - extensionName = extension.name, - onClickConfirm = { - onLongClickItem(extension) - showUninstallConfirmation = false - }, - onClickDismiss = { - showUninstallConfirmation = false - }, - onDismissRequest = { - showUninstallConfirmation = false - }, - ) - } - BaseBrowseItem( modifier = modifier .combinedClickable( onClick = { onClickItem(extension) }, - onLongClick = internalOnLongClickItem, + onLongClick = { onLongClickItem(extension) }, ), onClickItem = { onClickItem(extension) }, - onLongClickItem = internalOnLongClickItem, + onLongClickItem = { onLongClickItem(extension) }, icon = { Box( modifier = Modifier @@ -570,31 +540,3 @@ private fun ExtensionTrustDialog( onDismissRequest = onDismissRequest, ) } - -@Composable -private fun ExtensionUninstallConfirmation( - extensionName: String, - onClickConfirm: () -> Unit, - onClickDismiss: () -> Unit, - onDismissRequest: () -> Unit, -) { - AlertDialog( - title = { - Text(text = stringResource(MR.strings.ext_confirm_remove)) - }, - text = { - Text(text = stringResource(MR.strings.remove_private_extension_message, extensionName)) - }, - confirmButton = { - TextButton(onClick = onClickConfirm) { - Text(text = stringResource(MR.strings.ext_remove)) - } - }, - dismissButton = { - TextButton(onClick = onClickDismiss) { - Text(text = stringResource(MR.strings.action_cancel)) - } - }, - onDismissRequest = onDismissRequest, - ) -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt index be6d243b84..0c2c96063a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt @@ -1,8 +1,14 @@ package eu.kanade.tachiyomi.ui.browse.extension +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow import eu.kanade.presentation.browse.ExtensionScreen @@ -12,6 +18,7 @@ import eu.kanade.presentation.more.settings.screen.browse.ExtensionReposScreen import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsScreen import eu.kanade.tachiyomi.ui.webview.WebViewScreen +import eu.kanade.tachiyomi.util.system.isPackageInstalled import kotlinx.collections.immutable.persistentListOf import tachiyomi.i18n.MR import tachiyomi.presentation.core.i18n.stringResource @@ -22,6 +29,8 @@ fun extensionsTab( ): TabContent { val navigator = LocalNavigator.currentOrThrow val state by extensionsScreenModel.state.collectAsState() + val context = LocalContext.current + val showUninstallConfirmation = remember { mutableStateOf(null) } return TabContent( titleRes = MR.strings.label_extensions, @@ -45,7 +54,13 @@ fun extensionsTab( onLongClickItem = { extension -> when (extension) { is Extension.Available -> extensionsScreenModel.installExtension(extension) - else -> extensionsScreenModel.uninstallExtension(extension) + else -> { + if (context.isPackageInstalled(extension.pkgName)) { + extensionsScreenModel.uninstallExtension(extension) + } else { + showUninstallConfirmation.value = extension + } + } } }, onClickItemCancel = extensionsScreenModel::cancelInstallUpdateExtension, @@ -68,6 +83,50 @@ fun extensionsTab( onUpdateExtension = extensionsScreenModel::updateExtension, onRefresh = extensionsScreenModel::findAvailableExtensions, ) + + if (showUninstallConfirmation.value != null) { + ExtensionUninstallConfirmation( + extensionName = showUninstallConfirmation.value!!.name, + onClickConfirm = { + extensionsScreenModel.uninstallExtension(showUninstallConfirmation.value!!) + showUninstallConfirmation.value = null + }, + onClickDismiss = { + showUninstallConfirmation.value = null + }, + onDismissRequest = { + showUninstallConfirmation.value = null + }, + ) + } + }, + ) +} + +@Composable +private fun ExtensionUninstallConfirmation( + extensionName: String, + onClickConfirm: () -> Unit, + onClickDismiss: () -> Unit, + onDismissRequest: () -> Unit, +) { + AlertDialog( + title = { + Text(text = stringResource(MR.strings.ext_confirm_remove)) + }, + text = { + Text(text = stringResource(MR.strings.remove_private_extension_message, extensionName)) + }, + confirmButton = { + TextButton(onClick = onClickConfirm) { + Text(text = stringResource(MR.strings.ext_remove)) + } + }, + dismissButton = { + TextButton(onClick = onClickDismiss) { + Text(text = stringResource(MR.strings.action_cancel)) + } }, + onDismissRequest = onDismissRequest, ) } From 269645d12bd848aec3c2a9b222c7b590ea79658d Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Mon, 14 Oct 2024 00:43:11 +1300 Subject: [PATCH 4/6] Committing Some Suggestions --- .../ui/browse/extension/ExtensionsTab.kt | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt index 0c2c96063a..2ba2a55302 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt @@ -28,9 +28,10 @@ fun extensionsTab( extensionsScreenModel: ExtensionsScreenModel, ): TabContent { val navigator = LocalNavigator.currentOrThrow - val state by extensionsScreenModel.state.collectAsState() val context = LocalContext.current - val showUninstallConfirmation = remember { mutableStateOf(null) } + + val state by extensionsScreenModel.state.collectAsState() + val privateExtensionToUninstall = remember { mutableStateOf(null) } return TabContent( titleRes = MR.strings.label_extensions, @@ -58,7 +59,7 @@ fun extensionsTab( if (context.isPackageInstalled(extension.pkgName)) { extensionsScreenModel.uninstallExtension(extension) } else { - showUninstallConfirmation.value = extension + privateExtensionToUninstall.value = extension } } } @@ -84,18 +85,14 @@ fun extensionsTab( onRefresh = extensionsScreenModel::findAvailableExtensions, ) - if (showUninstallConfirmation.value != null) { + privateExtensionToUninstall.value?.let { extension -> ExtensionUninstallConfirmation( - extensionName = showUninstallConfirmation.value!!.name, + extensionName = privateExtensionToUninstall.value!!.name, onClickConfirm = { - extensionsScreenModel.uninstallExtension(showUninstallConfirmation.value!!) - showUninstallConfirmation.value = null - }, - onClickDismiss = { - showUninstallConfirmation.value = null + extensionsScreenModel.uninstallExtension(privateExtensionToUninstall.value!!) }, onDismissRequest = { - showUninstallConfirmation.value = null + privateExtensionToUninstall.value = null }, ) } @@ -107,7 +104,6 @@ fun extensionsTab( private fun ExtensionUninstallConfirmation( extensionName: String, onClickConfirm: () -> Unit, - onClickDismiss: () -> Unit, onDismissRequest: () -> Unit, ) { AlertDialog( @@ -118,12 +114,17 @@ private fun ExtensionUninstallConfirmation( Text(text = stringResource(MR.strings.remove_private_extension_message, extensionName)) }, confirmButton = { - TextButton(onClick = onClickConfirm) { + TextButton( + onClick = { + onClickConfirm() + onDismissRequest() + } + ) { Text(text = stringResource(MR.strings.ext_remove)) } }, dismissButton = { - TextButton(onClick = onClickDismiss) { + TextButton(onClick = onDismissRequest) { Text(text = stringResource(MR.strings.action_cancel)) } }, From 8824ad92b85ca5552a12993dc848d3cff2bb3376 Mon Sep 17 00:00:00 2001 From: Roshan Varughese <40583749+Animeboynz@users.noreply.github.com> Date: Mon, 14 Oct 2024 00:57:31 +1300 Subject: [PATCH 5/6] - Co-Authored-By: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../ui/browse/extension/ExtensionsTab.kt | 15 ++++++++------- .../commonMain/moko-resources/base/strings.xml | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt index 2ba2a55302..97dc6ebf08 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.currentOrThrow @@ -31,7 +32,7 @@ fun extensionsTab( val context = LocalContext.current val state by extensionsScreenModel.state.collectAsState() - val privateExtensionToUninstall = remember { mutableStateOf(null) } + var privateExtensionToUninstall by remember { mutableStateOf(null) } return TabContent( titleRes = MR.strings.label_extensions, @@ -59,7 +60,7 @@ fun extensionsTab( if (context.isPackageInstalled(extension.pkgName)) { extensionsScreenModel.uninstallExtension(extension) } else { - privateExtensionToUninstall.value = extension + privateExtensionToUninstall = extension } } } @@ -85,14 +86,14 @@ fun extensionsTab( onRefresh = extensionsScreenModel::findAvailableExtensions, ) - privateExtensionToUninstall.value?.let { extension -> + privateExtensionToUninstall?.let { extension -> ExtensionUninstallConfirmation( - extensionName = privateExtensionToUninstall.value!!.name, + extensionName = privateExtensionToUninstall!!.name, onClickConfirm = { - extensionsScreenModel.uninstallExtension(privateExtensionToUninstall.value!!) + extensionsScreenModel.uninstallExtension(privateExtensionToUninstall!!) }, onDismissRequest = { - privateExtensionToUninstall.value = null + privateExtensionToUninstall = null }, ) } @@ -118,7 +119,7 @@ private fun ExtensionUninstallConfirmation( onClick = { onClickConfirm() onDismissRequest() - } + }, ) { Text(text = stringResource(MR.strings.ext_remove)) } diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index 263f344453..4b92feaeb8 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -331,7 +331,7 @@ Untrusted extension Malicious extensions can read any stored login credentials or execute arbitrary code.\n\nBy trusting this extension, you accept these risks. This extension is no longer available. It may not function properly and can cause issues with the app. Uninstalling it is recommended. - Do you really want to remove the \"%s\" extension? + Do you really want to remove \"%s\" extension? Failed to fetch available extensions Version Language From 01bac7baa9787a71a3e811f52e495ba8ab5b3f56 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Sun, 13 Oct 2024 18:35:26 +0600 Subject: [PATCH 6/6] Update app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt --- .../eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt index 97dc6ebf08..bc91ea121d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionsTab.kt @@ -88,9 +88,9 @@ fun extensionsTab( privateExtensionToUninstall?.let { extension -> ExtensionUninstallConfirmation( - extensionName = privateExtensionToUninstall!!.name, + extensionName = extension.name, onClickConfirm = { - extensionsScreenModel.uninstallExtension(privateExtensionToUninstall!!) + extensionsScreenModel.uninstallExtension(extension) }, onDismissRequest = { privateExtensionToUninstall = null