Add support for the predictive back gesture
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
android:allowBackup="true"
|
||||
android:backupAgent="org.koitharu.kotatsu.settings.backup.AppBackupAgent"
|
||||
android:dataExtractionRules="@xml/backup_rules"
|
||||
android:enableOnBackInvokedCallback="true"
|
||||
android:fullBackupContent="@xml/backup_content"
|
||||
android:fullBackupOnly="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
@@ -39,6 +40,8 @@ abstract class AlertDialogFragment<B : ViewBinding> : DialogFragment() {
|
||||
|
||||
open fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder = builder
|
||||
|
||||
open fun onDialogCreated(dialog: AlertDialog) = Unit
|
||||
|
||||
protected fun bindingOrNull(): B? = viewBinding
|
||||
|
||||
protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B
|
||||
|
||||
@@ -82,6 +82,7 @@ abstract class BaseActivity<B : ViewBinding> :
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem) = if (item.itemId == android.R.id.home) {
|
||||
@Suppress("DEPRECATION")
|
||||
onBackPressed()
|
||||
true
|
||||
} else super.onOptionsItemSelected(item)
|
||||
@@ -130,7 +131,8 @@ abstract class BaseActivity<B : ViewBinding> :
|
||||
window.statusBarColor = getThemeColor(android.R.attr.statusBarColor)
|
||||
}
|
||||
|
||||
@Suppress("OVERRIDE_DEPRECATION", "DEPRECATION")
|
||||
@Suppress("DEPRECATION", "DeprecatedCallableAddReplaceWith")
|
||||
@Deprecated("Should not be used")
|
||||
override fun onBackPressed() {
|
||||
if ( // https://issuetracker.google.com/issues/139738913
|
||||
Build.VERSION.SDK_INT == Build.VERSION_CODES.Q &&
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams
|
||||
import androidx.activity.OnBackPressedDispatcher
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
@@ -30,6 +31,9 @@ abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
|
||||
val isExpanded: Boolean
|
||||
get() = behavior?.state == BottomSheetBehavior.STATE_EXPANDED
|
||||
|
||||
val onBackPressedDispatcher: OnBackPressedDispatcher
|
||||
get() = (requireDialog() as AppBottomSheetDialog).onBackPressedDispatcher
|
||||
|
||||
final override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.koitharu.kotatsu.base.ui.util
|
||||
|
||||
import android.view.MenuItem
|
||||
import android.view.MenuItem.OnActionExpandListener
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
|
||||
class CollapseActionViewCallback(
|
||||
private val menuItem: MenuItem
|
||||
) : OnBackPressedCallback(menuItem.isActionViewExpanded), OnActionExpandListener {
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
menuItem.collapseActionView()
|
||||
}
|
||||
|
||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||
isEnabled = true
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||
isEnabled = false
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,8 @@ import com.google.android.material.R as materialR
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback {
|
||||
|
||||
private lateinit var onBackPressedCallback: WebViewBackPressedCallback
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(ActivityBrowserBinding.inflate(layoutInflater))
|
||||
@@ -33,6 +35,8 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
|
||||
}
|
||||
binding.webView.webViewClient = BrowserClient(this)
|
||||
binding.webView.webChromeClient = ProgressChromeClient(binding.progressBar)
|
||||
onBackPressedCallback = WebViewBackPressedCallback(binding.webView)
|
||||
onBackPressedDispatcher.addCallback(onBackPressedCallback)
|
||||
if (savedInstanceState != null) {
|
||||
return
|
||||
}
|
||||
@@ -84,14 +88,6 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (binding.webView.canGoBack()) {
|
||||
binding.webView.goBack()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
binding.webView.onPause()
|
||||
super.onPause()
|
||||
@@ -116,6 +112,10 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
|
||||
supportActionBar?.subtitle = subtitle
|
||||
}
|
||||
|
||||
override fun onHistoryChanged() {
|
||||
onBackPressedCallback.onHistoryChanged()
|
||||
}
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) {
|
||||
binding.appbar.updatePadding(
|
||||
top = insets.top,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package org.koitharu.kotatsu.browser
|
||||
|
||||
interface BrowserCallback {
|
||||
interface BrowserCallback : OnHistoryChangedListener {
|
||||
|
||||
fun onLoadingStateChanged(isLoading: Boolean)
|
||||
|
||||
fun onTitleChanged(title: CharSequence, subtitle: CharSequence?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import android.graphics.Bitmap
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
|
||||
class BrowserClient(private val callback: BrowserCallback) : WebViewClient() {
|
||||
open class BrowserClient(private val callback: BrowserCallback) : WebViewClient() {
|
||||
|
||||
override fun onPageFinished(webView: WebView, url: String) {
|
||||
super.onPageFinished(webView, url)
|
||||
@@ -20,4 +20,9 @@ class BrowserClient(private val callback: BrowserCallback) : WebViewClient() {
|
||||
super.onPageCommitVisible(view, url)
|
||||
callback.onTitleChanged(view.title.orEmpty(), url)
|
||||
}
|
||||
}
|
||||
|
||||
override fun doUpdateVisitedHistory(view: WebView?, url: String?, isReload: Boolean) {
|
||||
super.doUpdateVisitedHistory(view, url, isReload)
|
||||
callback.onHistoryChanged()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.koitharu.kotatsu.browser
|
||||
|
||||
fun interface OnHistoryChangedListener {
|
||||
|
||||
fun onHistoryChanged()
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.koitharu.kotatsu.browser
|
||||
|
||||
import android.webkit.WebView
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
|
||||
class WebViewBackPressedCallback(
|
||||
private val webView: WebView,
|
||||
) : OnBackPressedCallback(false), OnHistoryChangedListener {
|
||||
|
||||
init {
|
||||
onHistoryChanged()
|
||||
}
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
webView.goBack()
|
||||
}
|
||||
|
||||
override fun onHistoryChanged() {
|
||||
isEnabled = webView.canGoBack()
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,14 @@
|
||||
package org.koitharu.kotatsu.browser.cloudflare
|
||||
|
||||
interface CloudFlareCallback {
|
||||
import org.koitharu.kotatsu.browser.BrowserCallback
|
||||
|
||||
interface CloudFlareCallback : BrowserCallback {
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) = Unit
|
||||
|
||||
override fun onTitleChanged(title: CharSequence, subtitle: CharSequence?) = Unit
|
||||
|
||||
fun onPageLoaded()
|
||||
|
||||
fun onCheckPassed()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ package org.koitharu.kotatsu.browser.cloudflare
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import org.koitharu.kotatsu.browser.BrowserClient
|
||||
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
|
||||
|
||||
private const val CF_CLEARANCE = "cf_clearance"
|
||||
@@ -12,22 +12,22 @@ class CloudFlareClient(
|
||||
private val cookieJar: MutableCookieJar,
|
||||
private val callback: CloudFlareCallback,
|
||||
private val targetUrl: String,
|
||||
) : WebViewClient() {
|
||||
) : BrowserClient(callback) {
|
||||
|
||||
private val oldClearance = getClearance()
|
||||
|
||||
override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
|
||||
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
|
||||
super.onPageStarted(view, url, favicon)
|
||||
checkClearance()
|
||||
}
|
||||
|
||||
override fun onPageCommitVisible(view: WebView?, url: String?) {
|
||||
override fun onPageCommitVisible(view: WebView, url: String?) {
|
||||
super.onPageCommitVisible(view, url)
|
||||
callback.onPageLoaded()
|
||||
}
|
||||
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
super.onPageFinished(view, url)
|
||||
override fun onPageFinished(webView: WebView, url: String) {
|
||||
super.onPageFinished(webView, url)
|
||||
callback.onPageLoaded()
|
||||
}
|
||||
|
||||
|
||||
@@ -8,12 +8,14 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.CookieManager
|
||||
import android.webkit.WebSettings
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import okhttp3.Headers
|
||||
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
|
||||
import org.koitharu.kotatsu.browser.WebViewBackPressedCallback
|
||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||
import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor
|
||||
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
|
||||
@@ -31,6 +33,8 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
|
||||
@Inject
|
||||
lateinit var cookieJar: MutableCookieJar
|
||||
|
||||
private var onBackPressedCallback: WebViewBackPressedCallback? = null
|
||||
|
||||
override fun onInflateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@@ -58,6 +62,7 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
|
||||
override fun onDestroyView() {
|
||||
binding.webView.stopLoading()
|
||||
binding.webView.destroy()
|
||||
onBackPressedCallback = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
@@ -65,6 +70,13 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
|
||||
return super.onBuildDialog(builder).setNegativeButton(android.R.string.cancel, null)
|
||||
}
|
||||
|
||||
override fun onDialogCreated(dialog: AlertDialog) {
|
||||
super.onDialogCreated(dialog)
|
||||
onBackPressedCallback = WebViewBackPressedCallback(binding.webView).also {
|
||||
dialog.onBackPressedDispatcher.addCallback(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
binding.webView.onResume()
|
||||
@@ -89,6 +101,10 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
override fun onHistoryChanged() {
|
||||
onBackPressedCallback?.onHistoryChanged()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val TAG = "CloudFlareDialog"
|
||||
|
||||
@@ -1,34 +1,29 @@
|
||||
package org.koitharu.kotatsu.list.ui.filter
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.AsyncListDiffer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.base.ui.util.CollapseActionViewCallback
|
||||
import org.koitharu.kotatsu.databinding.SheetFilterBinding
|
||||
import org.koitharu.kotatsu.remotelist.ui.RemoteListViewModel
|
||||
import org.koitharu.kotatsu.utils.ext.isScrolledToTop
|
||||
import org.koitharu.kotatsu.utils.ext.parentFragmentViewModels
|
||||
|
||||
class FilterBottomSheet :
|
||||
BaseBottomSheet<SheetFilterBinding>(),
|
||||
MenuItem.OnActionExpandListener,
|
||||
SearchView.OnQueryTextListener,
|
||||
DialogInterface.OnKeyListener,
|
||||
AsyncListDiffer.ListListener<FilterItem> {
|
||||
|
||||
private val viewModel by parentFragmentViewModels<RemoteListViewModel>()
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).also {
|
||||
it.setOnKeyListener(this)
|
||||
}
|
||||
}
|
||||
private var collapsibleActionViewCallback: CollapseActionViewCallback? = null
|
||||
|
||||
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): SheetFilterBinding {
|
||||
return SheetFilterBinding.inflate(inflater, container, false)
|
||||
@@ -42,8 +37,14 @@ class FilterBottomSheet :
|
||||
initOptionsMenu()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
collapsibleActionViewCallback = null
|
||||
}
|
||||
|
||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||
setExpanded(isExpanded = true, isLocked = true)
|
||||
collapsibleActionViewCallback?.onMenuItemActionExpand(item)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -51,6 +52,7 @@ class FilterBottomSheet :
|
||||
val searchView = (item.actionView as? SearchView) ?: return false
|
||||
searchView.setQuery("", false)
|
||||
searchView.post { setExpanded(isExpanded = false, isLocked = false) }
|
||||
collapsibleActionViewCallback?.onMenuItemActionCollapse(item)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -61,19 +63,6 @@ class FilterBottomSheet :
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onKey(dialog: DialogInterface?, keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
val menuItem = binding.headerBar.toolbar.menu.findItem(R.id.action_search) ?: return false
|
||||
if (menuItem.isActionViewExpanded) {
|
||||
if (event?.action == KeyEvent.ACTION_UP) {
|
||||
menuItem.collapseActionView()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onCurrentListChanged(previousList: MutableList<FilterItem>, currentList: MutableList<FilterItem>) {
|
||||
if (currentList.size > previousList.size && view != null) {
|
||||
(binding.recyclerView.layoutManager as LinearLayoutManager).scrollToPositionWithOffset(0, 0)
|
||||
@@ -81,13 +70,16 @@ class FilterBottomSheet :
|
||||
}
|
||||
|
||||
private fun initOptionsMenu() {
|
||||
binding.headerBar.toolbar.inflateMenu(R.menu.opt_filter)
|
||||
val searchMenuItem = binding.headerBar.toolbar.menu.findItem(R.id.action_search)
|
||||
binding.headerBar.inflateMenu(R.menu.opt_filter)
|
||||
val searchMenuItem = binding.headerBar.menu.findItem(R.id.action_search)
|
||||
searchMenuItem.setOnActionExpandListener(this)
|
||||
val searchView = searchMenuItem.actionView as SearchView
|
||||
searchView.setOnQueryTextListener(this)
|
||||
searchView.setIconifiedByDefault(false)
|
||||
searchView.queryHint = searchMenuItem.title
|
||||
collapsibleActionViewCallback = CollapseActionViewCallback(searchMenuItem).also {
|
||||
onBackPressedDispatcher.addCallback(it)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.os.Bundle
|
||||
import android.util.SparseIntArray
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.result.ActivityResultCallback
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.view.ActionMode
|
||||
@@ -84,6 +85,7 @@ class MainActivity :
|
||||
private val viewModel by viewModels<MainViewModel>()
|
||||
private val searchSuggestionViewModel by viewModels<SearchSuggestionViewModel>()
|
||||
private val voiceInputLauncher = registerForActivityResult(VoiceInputContract(), VoiceInputCallback())
|
||||
private val closeSearchCallback = CloseSearchCallback()
|
||||
private lateinit var navigationDelegate: MainNavigationDelegate
|
||||
|
||||
override val appBar: AppBarLayout
|
||||
@@ -121,8 +123,9 @@ class MainActivity :
|
||||
navigationDelegate.addOnFragmentChangedListener(this)
|
||||
navigationDelegate.onCreate(savedInstanceState)
|
||||
|
||||
onBackPressedDispatcher.addCallback(navigationDelegate)
|
||||
onBackPressedDispatcher.addCallback(ExitCallback(this, binding.container))
|
||||
onBackPressedDispatcher.addCallback(navigationDelegate)
|
||||
onBackPressedDispatcher.addCallback(closeSearchCallback)
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
onFirstStart()
|
||||
@@ -142,21 +145,6 @@ class MainActivity :
|
||||
adjustSearchUI(isSearchOpened(), animate = false)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
val fragment = supportFragmentManager.findFragmentByTag(TAG_SEARCH)
|
||||
binding.searchView.clearFocus()
|
||||
when {
|
||||
fragment != null -> supportFragmentManager.commit {
|
||||
setReorderingAllowed(true)
|
||||
remove(fragment)
|
||||
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
runOnCommit { onSearchClosed() }
|
||||
}
|
||||
|
||||
else -> super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFragmentChanged(fragment: Fragment, fromUser: Boolean) {
|
||||
adjustFabVisibility(topFragment = fragment)
|
||||
if (fromUser) {
|
||||
@@ -300,11 +288,13 @@ class MainActivity :
|
||||
|
||||
private fun onSearchOpened() {
|
||||
adjustSearchUI(isOpened = true, animate = true)
|
||||
closeSearchCallback.isEnabled = true
|
||||
}
|
||||
|
||||
private fun onSearchClosed() {
|
||||
binding.searchView.hideKeyboard()
|
||||
adjustSearchUI(isOpened = false, animate = true)
|
||||
closeSearchCallback.isEnabled = false
|
||||
}
|
||||
|
||||
private fun showNav(visible: Boolean) {
|
||||
@@ -406,4 +396,23 @@ class MainActivity :
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class CloseSearchCallback : OnBackPressedCallback(false) {
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
val fragment = supportFragmentManager.findFragmentByTag(TAG_SEARCH)
|
||||
binding.searchView.clearFocus()
|
||||
if (fragment == null) {
|
||||
// this should not happen but who knows
|
||||
isEnabled = false
|
||||
return
|
||||
}
|
||||
supportFragmentManager.commit {
|
||||
setReorderingAllowed(true)
|
||||
remove(fragment)
|
||||
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
|
||||
runOnCommit { onSearchClosed() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package org.koitharu.kotatsu.scrobbling.common.ui.selector
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
@@ -20,6 +17,7 @@ import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||
import org.koitharu.kotatsu.base.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.base.ui.list.PaginationScrollListener
|
||||
import org.koitharu.kotatsu.base.ui.util.CollapseActionViewCallback
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.databinding.SheetScrobblingSelectorBinding
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
|
||||
@@ -43,7 +41,6 @@ class ScrobblingSelectorBottomSheet :
|
||||
View.OnClickListener,
|
||||
MenuItem.OnActionExpandListener,
|
||||
SearchView.OnQueryTextListener,
|
||||
DialogInterface.OnKeyListener,
|
||||
TabLayout.OnTabSelectedListener,
|
||||
ListStateHolderListener {
|
||||
|
||||
@@ -53,6 +50,8 @@ class ScrobblingSelectorBottomSheet :
|
||||
@Inject
|
||||
lateinit var coil: ImageLoader
|
||||
|
||||
private var collapsibleActionViewCallback: CollapseActionViewCallback? = null
|
||||
|
||||
private val viewModel by assistedViewModels {
|
||||
viewModelFactory.create(
|
||||
requireArguments().requireParcelable<ParcelableManga>(MangaIntent.KEY_MANGA).manga,
|
||||
@@ -63,12 +62,6 @@ class ScrobblingSelectorBottomSheet :
|
||||
return SheetScrobblingSelectorBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).also {
|
||||
it.setOnKeyListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val listAdapter = ScrobblerSelectorAdapter(viewLifecycleOwner, coil, this, this)
|
||||
@@ -102,6 +95,11 @@ class ScrobblingSelectorBottomSheet :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
collapsibleActionViewCallback = null
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.button_done -> viewModel.onDoneClick()
|
||||
@@ -126,6 +124,7 @@ class ScrobblingSelectorBottomSheet :
|
||||
|
||||
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||
setExpanded(isExpanded = true, isLocked = true)
|
||||
collapsibleActionViewCallback?.onMenuItemActionExpand(item)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -133,6 +132,7 @@ class ScrobblingSelectorBottomSheet :
|
||||
val searchView = (item.actionView as? SearchView) ?: return false
|
||||
searchView.setQuery("", false)
|
||||
searchView.post { setExpanded(isExpanded = false, isLocked = false) }
|
||||
collapsibleActionViewCallback?.onMenuItemActionCollapse(item)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -147,19 +147,6 @@ class ScrobblingSelectorBottomSheet :
|
||||
|
||||
override fun onQueryTextChange(newText: String?): Boolean = false
|
||||
|
||||
override fun onKey(dialog: DialogInterface?, keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
val menuItem = binding.headerBar.menu.findItem(R.id.action_search) ?: return false
|
||||
if (menuItem.isActionViewExpanded) {
|
||||
if (event?.action == KeyEvent.ACTION_UP) {
|
||||
menuItem.collapseActionView()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onTabSelected(tab: TabLayout.Tab) {
|
||||
viewModel.setScrobblerIndex(tab.position)
|
||||
}
|
||||
@@ -193,6 +180,9 @@ class ScrobblingSelectorBottomSheet :
|
||||
searchView.setOnQueryTextListener(this)
|
||||
searchView.setIconifiedByDefault(false)
|
||||
searchView.queryHint = searchMenuItem.title
|
||||
collapsibleActionViewCallback = CollapseActionViewCallback(searchMenuItem).also {
|
||||
onBackPressedDispatcher.addCallback(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initTabs() {
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||
import org.koitharu.kotatsu.browser.BrowserCallback
|
||||
import org.koitharu.kotatsu.browser.BrowserClient
|
||||
import org.koitharu.kotatsu.browser.ProgressChromeClient
|
||||
import org.koitharu.kotatsu.browser.WebViewBackPressedCallback
|
||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||
import org.koitharu.kotatsu.core.network.CommonHeadersInterceptor
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
@@ -34,6 +35,7 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
|
||||
@Inject
|
||||
lateinit var mangaRepositoryFactory: MangaRepository.Factory
|
||||
|
||||
private lateinit var onBackPressedCallback: WebViewBackPressedCallback
|
||||
private lateinit var authProvider: MangaParserAuthProvider
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@@ -66,6 +68,8 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
|
||||
}
|
||||
binding.webView.webViewClient = BrowserClient(this)
|
||||
binding.webView.webChromeClient = ProgressChromeClient(binding.progressBar)
|
||||
onBackPressedCallback = WebViewBackPressedCallback(binding.webView)
|
||||
onBackPressedDispatcher.addCallback(onBackPressedCallback)
|
||||
if (savedInstanceState != null) {
|
||||
return
|
||||
}
|
||||
@@ -103,14 +107,6 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (binding.webView.canGoBack()) {
|
||||
binding.webView.goBack()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
binding.webView.onPause()
|
||||
super.onPause()
|
||||
@@ -135,6 +131,10 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
|
||||
supportActionBar?.subtitle = subtitle
|
||||
}
|
||||
|
||||
override fun onHistoryChanged() {
|
||||
onBackPressedCallback.onHistoryChanged()
|
||||
}
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) {
|
||||
binding.appbar.updatePadding(top = insets.top)
|
||||
binding.webView.updatePadding(bottom = insets.bottom)
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.graphics.Insets
|
||||
import androidx.core.view.isGone
|
||||
@@ -28,6 +29,7 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
|
||||
private var accountAuthenticatorResponse: AccountAuthenticatorResponse? = null
|
||||
private var resultBundle: Bundle? = null
|
||||
private val pageBackCallback = PageBackCallback()
|
||||
|
||||
private val viewModel by viewModels<SyncAuthViewModel>()
|
||||
|
||||
@@ -44,9 +46,13 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
binding.editEmail.addTextChangedListener(EmailTextWatcher(binding.buttonNext))
|
||||
binding.editPassword.addTextChangedListener(PasswordTextWatcher(binding.buttonDone))
|
||||
|
||||
onBackPressedDispatcher.addCallback(pageBackCallback)
|
||||
|
||||
viewModel.onTokenObtained.observe(this, ::onTokenReceived)
|
||||
viewModel.onError.observe(this, ::onError)
|
||||
viewModel.isLoading.observe(this, ::onLoadingStateChanged)
|
||||
|
||||
pageBackCallback.update()
|
||||
}
|
||||
|
||||
override fun onWindowInsetsChanged(insets: Insets) {
|
||||
@@ -59,27 +65,23 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
|
||||
override fun onBackPressed() {
|
||||
if (binding.switcher.isVisible && binding.switcher.displayedChild > 0) {
|
||||
binding.switcher.showPrevious()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.button_cancel -> {
|
||||
setResult(RESULT_CANCELED)
|
||||
finish()
|
||||
}
|
||||
|
||||
R.id.button_next -> {
|
||||
binding.switcher.showNext()
|
||||
pageBackCallback.update()
|
||||
}
|
||||
|
||||
R.id.button_back -> {
|
||||
binding.switcher.showPrevious()
|
||||
pageBackCallback.update()
|
||||
}
|
||||
|
||||
R.id.button_done -> {
|
||||
viewModel.obtainToken(
|
||||
email = binding.editEmail.text.toString(),
|
||||
@@ -105,6 +107,7 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
TransitionManager.beginDelayedTransition(binding.root, Fade())
|
||||
binding.switcher.isGone = isLoading
|
||||
binding.layoutProgress.isVisible = isLoading
|
||||
pageBackCallback.update()
|
||||
}
|
||||
|
||||
private fun onError(error: Throwable) {
|
||||
@@ -161,4 +164,16 @@ class SyncAuthActivity : BaseActivity<ActivitySyncAuthBinding>(), View.OnClickLi
|
||||
button.isEnabled = text != null && text.length >= 4
|
||||
}
|
||||
}
|
||||
|
||||
private inner class PageBackCallback : OnBackPressedCallback(false) {
|
||||
|
||||
override fun handleOnBackPressed() {
|
||||
binding.switcher.showPrevious()
|
||||
update()
|
||||
}
|
||||
|
||||
fun update() {
|
||||
isEnabled = binding.switcher.isVisible && binding.switcher.displayedChild > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user