Add IME_FLAG_NO_PERSONALIZED_LEARNING flag to text input when incognito is enabled

Tested with Gboard only.
This commit is contained in:
Ivan Iskandar 2021-08-27 20:57:28 +07:00
parent 4b2a9bc621
commit 068399dbb3
No known key found for this signature in database
GPG Key ID: 2C57784F9E46D60D
9 changed files with 92 additions and 5 deletions

View File

@ -9,6 +9,9 @@ import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.Router import com.bluelinelabs.conductor.Router
import com.bluelinelabs.conductor.RouterTransaction import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler import com.bluelinelabs.conductor.changehandler.SimpleSwapChangeHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.cancel
/** /**
* A controller that displays a dialog window, floating on top of its activity's window. * A controller that displays a dialog window, floating on top of its activity's window.
@ -23,6 +26,22 @@ abstract class DialogController : Controller {
private var dismissed = false private var dismissed = false
lateinit var lifecycleScope: CoroutineScope
init {
addLifecycleListener(
object : LifecycleListener() {
override fun preCreateView(controller: Controller) {
lifecycleScope = MainScope()
}
override fun preDestroyView(controller: Controller, view: View) {
lifecycleScope.cancel()
}
}
)
}
/** /**
* Convenience constructor for use when no arguments are needed. * Convenience constructor for use when no arguments are needed.
*/ */

View File

@ -9,6 +9,7 @@ import androidx.annotation.StringRes
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.util.view.setIncognitoFlow
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.appcompat.QueryTextEvent import reactivecircus.flowbinding.appcompat.QueryTextEvent
@ -49,9 +50,17 @@ abstract class SearchableNucleusController<VB : ViewBinding, P : BasePresenter<*
// Initialize search option. // Initialize search option.
val searchItem = menu.findItem(searchItemId) val searchItem = menu.findItem(searchItemId)
val searchView = searchItem.actionView as SearchView val searchView = searchItem.actionView as SearchView
searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() }) searchItem.fixExpand(
onExpand = {
val result = invalidateMenuOnExpand()
// For BrowseSourceController :)
searchView.setIncognitoFlow(viewScope)
result
}
)
searchView.maxWidth = Int.MAX_VALUE searchView.maxWidth = Int.MAX_VALUE
searchView.setIncognitoFlow(viewScope)
searchView.queryTextEvents() searchView.queryTextEvents()
.onEach { .onEach {
val newText = it.queryText.toString() val newText = it.queryText.toString()

View File

@ -19,6 +19,7 @@ import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.browse.BrowseController import eu.kanade.tachiyomi.ui.browse.BrowseController
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsController import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsController
import eu.kanade.tachiyomi.util.view.setIncognitoFlow
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -127,7 +128,13 @@ open class ExtensionController :
searchView.maxWidth = Int.MAX_VALUE searchView.maxWidth = Int.MAX_VALUE
// Fixes problem with the overflow icon showing up in lieu of search // Fixes problem with the overflow icon showing up in lieu of search
searchItem.fixExpand(onExpand = { invalidateMenuOnExpand() }) searchItem.fixExpand(
onExpand = {
val result = invalidateMenuOnExpand()
searchView.setIncognitoFlow(viewScope)
result
}
)
if (query.isNotEmpty()) { if (query.isNotEmpty()) {
searchItem.expandActionView() searchItem.expandActionView()

View File

@ -32,7 +32,7 @@ class CategoryCreateDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
override fun onCreateDialog(savedViewState: Bundle?): Dialog { override fun onCreateDialog(savedViewState: Bundle?): Dialog {
return MaterialAlertDialogBuilder(activity!!) return MaterialAlertDialogBuilder(activity!!)
.setTitle(R.string.action_add_category) .setTitle(R.string.action_add_category)
.setTextInput(prefill = currentName) { .setTextInput(lifecycleScope = lifecycleScope, prefill = currentName) {
currentName = it currentName = it
} }
.setPositiveButton(android.R.string.ok) { _, _ -> .setPositiveButton(android.R.string.ok) { _, _ ->

View File

@ -37,7 +37,7 @@ class CategoryRenameDialog<T>(bundle: Bundle? = null) : DialogController(bundle)
override fun onCreateDialog(savedViewState: Bundle?): Dialog { override fun onCreateDialog(savedViewState: Bundle?): Dialog {
return MaterialAlertDialogBuilder(activity!!) return MaterialAlertDialogBuilder(activity!!)
.setTitle(R.string.action_rename_category) .setTitle(R.string.action_rename_category)
.setTextInput(prefill = currentName) { .setTextInput(lifecycleScope = lifecycleScope, prefill = currentName) {
currentName = it currentName = it
} }
.setPositiveButton(android.R.string.ok) { _, _ -> onPositive() } .setPositiveButton(android.R.string.ok) { _, _ -> onPositive() }

View File

@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.databinding.TrackSearchDialogBinding import eu.kanade.tachiyomi.databinding.TrackSearchDialogBinding
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.manga.MangaController import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.util.view.setIncognitoFlow
import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat import eu.kanade.tachiyomi.util.view.setNavigationBarTransparentCompat
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
@ -92,6 +93,7 @@ class TrackSearchDialog : DialogController {
search(currentlySearched) search(currentlySearched)
// Input listener // Input listener
binding?.titleInput?.editText?.setIncognitoFlow(trackController.viewScope)
binding?.titleInput?.editText binding?.titleInput?.editText
?.editorActionEvents { ?.editorActionEvents {
when (it.actionId) { when (it.actionId) {

View File

@ -28,6 +28,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.onAnimationsFinished import eu.kanade.tachiyomi.util.view.onAnimationsFinished
import eu.kanade.tachiyomi.util.view.setIncognitoFlow
import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
@ -208,7 +209,11 @@ class HistoryController :
// Fixes problem with the overflow icon showing up in lieu of search // Fixes problem with the overflow icon showing up in lieu of search
searchItem.fixExpand( searchItem.fixExpand(
onExpand = { invalidateMenuOnExpand() } onExpand = {
val result = invalidateMenuOnExpand()
searchView.setIncognitoFlow(viewScope)
result
}
) )
} }

View File

@ -10,16 +10,19 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText
import android.widget.TextView import android.widget.TextView
import androidx.annotation.MenuRes import androidx.annotation.MenuRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.view.menu.MenuBuilder import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.TooltipCompat import androidx.appcompat.widget.TooltipCompat
import androidx.core.view.children import androidx.core.view.children
import androidx.core.view.descendants import androidx.core.view.descendants
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.core.view.inputmethod.EditorInfoCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.ViewPager import androidx.viewpager.widget.ViewPager
import com.google.android.material.card.MaterialCardView import com.google.android.material.card.MaterialCardView
@ -29,8 +32,14 @@ import com.google.android.material.elevation.ElevationOverlayProvider
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.isNightMode import eu.kanade.tachiyomi.util.system.isNightMode
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
/** /**
* Returns coordinates of view. * Returns coordinates of view.
@ -255,3 +264,35 @@ fun ViewPager.getActivePageView(): View? {
false false
} }
} }
/**
* Sets Flow to this [SearchView] that sets [EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING] to imeOptions
* if [PreferencesHelper.incognitoMode] is true.
*
* Some IMEs may not respect this flag.
*/
fun SearchView.setIncognitoFlow(viewScope: CoroutineScope) {
Injekt.get<PreferencesHelper>().incognitoMode().asImmediateFlow {
imeOptions = if (it) {
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
} else {
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
}
}.launchIn(viewScope)
}
/**
* Sets Flow to this [EditText] that sets [EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING] to imeOptions
* if [PreferencesHelper.incognitoMode] is true.
*
* Some IMEs may not respect this flag.
*/
fun EditText.setIncognitoFlow(viewScope: CoroutineScope) {
Injekt.get<PreferencesHelper>().incognitoMode().asImmediateFlow {
imeOptions = if (it) {
imeOptions or EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING
} else {
imeOptions and EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING.inv()
}
}.launchIn(viewScope)
}

View File

@ -11,8 +11,11 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.tachiyomi.databinding.DialogStubQuadstatemultichoiceBinding import eu.kanade.tachiyomi.databinding.DialogStubQuadstatemultichoiceBinding
import eu.kanade.tachiyomi.databinding.DialogStubTextinputBinding import eu.kanade.tachiyomi.databinding.DialogStubTextinputBinding
import eu.kanade.tachiyomi.util.view.setIncognitoFlow
import kotlinx.coroutines.CoroutineScope
fun MaterialAlertDialogBuilder.setTextInput( fun MaterialAlertDialogBuilder.setTextInput(
lifecycleScope: CoroutineScope,
hint: String? = null, hint: String? = null,
prefill: String? = null, prefill: String? = null,
onTextChanged: (String) -> Unit onTextChanged: (String) -> Unit
@ -20,6 +23,7 @@ fun MaterialAlertDialogBuilder.setTextInput(
val binding = DialogStubTextinputBinding.inflate(LayoutInflater.from(context)) val binding = DialogStubTextinputBinding.inflate(LayoutInflater.from(context))
binding.textField.hint = hint binding.textField.hint = hint
binding.textField.editText?.apply { binding.textField.editText?.apply {
setIncognitoFlow(lifecycleScope)
setText(prefill, TextView.BufferType.EDITABLE) setText(prefill, TextView.BufferType.EDITABLE)
doAfterTextChanged { doAfterTextChanged {
onTextChanged(it?.toString() ?: "") onTextChanged(it?.toString() ?: "")