From 3fdc28972025b9c2be0f798c4bf423fdd8ee4cf0 Mon Sep 17 00:00:00 2001 From: Acclorite <140836141+Acclorite@users.noreply.github.com> Date: Wed, 14 Aug 2024 21:12:29 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=80=20Add=20new=20text=20selection=20a?= =?UTF-8?q?ctions=20(Share/Web)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added new actions to text selection toolbar. Share action shares selected text to the app you want to. Web Search action searches selected text in your browser. Partly resolves: #46 --- .../components/CustomSelectionContainer.kt | 67 +++++++++++++++++-- .../screens/reader/ReaderScreen.kt | 32 ++++++++- .../screens/reader/data/ReaderEvent.kt | 12 ++++ .../screens/reader/data/ReaderViewModel.kt | 49 ++++++++++++++ app/src/main/res/values-uk/strings.xml | 4 ++ app/src/main/res/values/strings.xml | 4 ++ 6 files changed, 162 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/components/CustomSelectionContainer.kt b/app/src/main/java/ua/acclorite/book_story/presentation/components/CustomSelectionContainer.kt index 0f4fba42..3944725f 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/components/CustomSelectionContainer.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/components/CustomSelectionContainer.kt @@ -29,8 +29,10 @@ import ua.acclorite.book_story.R private const val MENU_ITEM_COPY = 0 -private const val MENU_ITEM_TRANSLATE = 1 -private const val MENU_ITEM_DICTIONARY = 2 +private const val MENU_ITEM_SHARE = 1 +private const val MENU_ITEM_WEB = 2 +private const val MENU_ITEM_TRANSLATE = 3 +private const val MENU_ITEM_DICTIONARY = 4 /** * Custom Text ActionMode callback. Used in pair with [CustomSelectionToolbar]. Follow [TextToolbar] for more info. @@ -39,6 +41,8 @@ private class CustomTextActionModeCallback( private val context: Context, var rect: Rect = Rect.Zero, var onCopyRequested: (() -> Unit)? = null, + var onShareRequested: (() -> Unit)? = null, + var onWebSearchRequested: (() -> Unit)? = null, var onTranslateRequested: (() -> Unit)? = null, var onDictionaryRequested: (() -> Unit)? = null ) : ActionMode.Callback { @@ -51,13 +55,23 @@ private class CustomTextActionModeCallback( .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) } + onShareRequested?.let { + menu.add(0, MENU_ITEM_SHARE, 1, context.getString(R.string.share)) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) + } + + onWebSearchRequested?.let { + menu.add(0, MENU_ITEM_WEB, 2, context.getString(R.string.web_search)) + .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) + } + onTranslateRequested?.let { - menu.add(0, MENU_ITEM_TRANSLATE, 1, context.getString(R.string.translate)) + menu.add(0, MENU_ITEM_TRANSLATE, 3, context.getString(R.string.translate)) .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) } onDictionaryRequested?.let { - menu.add(0, MENU_ITEM_DICTIONARY, 2, context.getString(R.string.dictionary)) + menu.add(0, MENU_ITEM_DICTIONARY, 4, context.getString(R.string.dictionary)) .setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER) } @@ -71,6 +85,8 @@ private class CustomTextActionModeCallback( override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean { when (item!!.itemId) { MENU_ITEM_COPY -> onCopyRequested?.invoke() + MENU_ITEM_SHARE -> onShareRequested?.invoke() + MENU_ITEM_WEB -> onWebSearchRequested?.invoke() MENU_ITEM_TRANSLATE -> onTranslateRequested?.invoke() MENU_ITEM_DICTIONARY -> onDictionaryRequested?.invoke() else -> return false @@ -116,12 +132,15 @@ private class FloatingTextActionModeCallback( } /** - * Custom Selection Toolbar. Used in pair with [CustomSelectionContainer] to display custom toolbar. + * Custom Selection Toolbar. + * Used in pair with [CustomSelectionContainer] to display custom toolbar. */ private class CustomSelectionToolbar( private val view: View, context: Context, private val onCopyRequest: (() -> Unit)?, + private val onShareRequest: ((String) -> Unit)?, + private val onWebSearchRequest: ((String) -> Unit)?, private val onTranslateRequest: ((String) -> Unit)?, private val onDictionaryRequest: ((String) -> Unit)? ) : TextToolbar { @@ -145,6 +164,36 @@ private class CustomSelectionToolbar( onCopyRequested?.invoke() onCopyRequest?.invoke() } + callback.onShareRequested = { + val previousClipboard = clipboardManager.primaryClip + onCopyRequested?.invoke() + val currentClipboard = clipboardManager.text + + onShareRequest?.invoke(currentClipboard.toString()) + + if (previousClipboard != null) { + clipboardManager.setPrimaryClip( + previousClipboard + ) + } else { + clipboardManager.setPrimaryClip(ClipData.newPlainText(null, " ")) + } + } + callback.onWebSearchRequested = { + val previousClipboard = clipboardManager.primaryClip + onCopyRequested?.invoke() + val currentClipboard = clipboardManager.text + + onWebSearchRequest?.invoke(currentClipboard.toString()) + + if (previousClipboard != null) { + clipboardManager.setPrimaryClip( + previousClipboard + ) + } else { + clipboardManager.setPrimaryClip(ClipData.newPlainText(null, " ")) + } + } callback.onTranslateRequested = { val previousClipboard = clipboardManager.primaryClip onCopyRequested?.invoke() @@ -205,6 +254,8 @@ private class CustomSelectionToolbar( @Composable fun CustomSelectionContainer( onCopyRequested: (() -> Unit), + onShareRequested: ((String) -> Unit), + onWebSearchRequested: ((String) -> Unit), onTranslateRequested: ((String) -> Unit), onDictionaryRequested: ((String) -> Unit), content: @Composable (toolbarHidden: Boolean) -> Unit @@ -220,6 +271,12 @@ fun CustomSelectionContainer( onCopyRequest = { onCopyRequested() }, + onShareRequest = { + onShareRequested(it) + }, + onWebSearchRequest = { + onWebSearchRequested(it) + }, onTranslateRequest = { onTranslateRequested(it) }, diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt index 951a0c19..9c3c0a53 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/ReaderScreen.kt @@ -274,6 +274,36 @@ private fun ReaderScreen( ).show() } }, + onShareRequested = { textToShare -> + onEvent( + ReaderEvent.OnOpenShareApp( + textToShare = textToShare, + context, + noAppsFound = { + Toast.makeText( + context, + context.getString(R.string.error_no_share_app), + Toast.LENGTH_SHORT + ).show() + } + ) + ) + }, + onWebSearchRequested = { textToSearch -> + onEvent( + ReaderEvent.OnOpenWebBrowser( + textToSearch = textToSearch, + context, + noAppsFound = { + Toast.makeText( + context, + context.getString(R.string.error_no_browser), + Toast.LENGTH_SHORT + ).show() + } + ) + ) + }, onTranslateRequested = { textToTranslate -> onEvent( ReaderEvent.OnOpenTranslator( @@ -298,7 +328,7 @@ private fun ReaderScreen( noAppsFound = { Toast.makeText( context, - context.getString(R.string.error_no_browser), + context.getString(R.string.error_no_dictionary), Toast.LENGTH_SHORT ).show() } diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderEvent.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderEvent.kt index 1fc25861..36a149af 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderEvent.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderEvent.kt @@ -51,6 +51,18 @@ sealed class ReaderEvent { val noAppsFound: () -> Unit ) : ReaderEvent() + data class OnOpenShareApp( + val textToShare: String, + val context: ComponentActivity, + val noAppsFound: () -> Unit + ) : ReaderEvent() + + data class OnOpenWebBrowser( + val textToSearch: String, + val context: ComponentActivity, + val noAppsFound: () -> Unit + ) : ReaderEvent() + data class OnOpenDictionary( val textToDefine: String, val context: ComponentActivity, diff --git a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderViewModel.kt b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderViewModel.kt index 98dccf54..2f74e5c0 100644 --- a/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderViewModel.kt +++ b/app/src/main/java/ua/acclorite/book_story/presentation/screens/reader/data/ReaderViewModel.kt @@ -360,6 +360,55 @@ class ReaderViewModel @Inject constructor( } } + is ReaderEvent.OnOpenShareApp -> { + launch { + val shareIntent = Intent() + + shareIntent.action = Intent.ACTION_SEND + shareIntent.type = "text/plain" + shareIntent.putExtra( + Intent.EXTRA_SUBJECT, + event.context.getString(R.string.app_name) + ) + shareIntent.putExtra( + Intent.EXTRA_TEXT, + event.textToShare.trim() + ) + + var shareFailure = false + shareIntent.launchActivity(event.context, createChooser = true) { + shareFailure = true + } + if (!shareFailure) { + return@launch + } + + event.noAppsFound() + } + } + + is ReaderEvent.OnOpenWebBrowser -> { + launch { + val browserIntent = Intent() + + browserIntent.action = Intent.ACTION_WEB_SEARCH + browserIntent.putExtra( + SearchManager.QUERY, + event.textToSearch + ) + + var browserFailure = false + browserIntent.launchActivity(event.context) { + browserFailure = true + } + if (!browserFailure) { + return@launch + } + + event.noAppsFound() + } + } + is ReaderEvent.OnOpenDictionary -> { launch { val dictionaryIntent = Intent() diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 497e2f34..6d393843 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -101,7 +101,9 @@ Помилка: %1$s Цей файл пустий або пошкоджений. Не знайдено жодного перекладача. + Не знайдено жодного словника. Не знайдено жодного браузера. + Не знайдено застосунка щоб поділитися. Вміст книги пустий. Будь ласка, перевірте вміст книги та оновіть її. @@ -160,6 +162,8 @@ Завантажити Готово Увімкнути + Веб-пошук + Поділитися файли diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 86cbf832..e2480a92 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -118,7 +118,9 @@ Error: %1$s This file is empty or corrupted. No translator app found. + No dictionary app found. No browser app found. + No app to share found. The book content is empty. Please, make sure that the book content is not empty and update it. @@ -176,6 +178,8 @@ Download Done Enable + Web search + Share files