Better back press handling

This commit is contained in:
kitsunyan
2020-07-04 03:14:23 +03:00
parent c34574c014
commit ba3936311e
10 changed files with 61 additions and 49 deletions
@@ -1,6 +0,0 @@
package nya.kitsunyan.foxydroid.screen
import androidx.fragment.app.Fragment
val Fragment.screenActivity: ScreenActivity
get() = requireActivity() as ScreenActivity
@@ -20,7 +20,6 @@ import android.widget.FrameLayout
import android.widget.TextView import android.widget.TextView
import android.widget.Toolbar import android.widget.Toolbar
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.core.Single
@@ -44,7 +43,7 @@ import java.nio.charset.Charset
import java.util.Locale import java.util.Locale
import kotlin.math.* import kotlin.math.*
class EditRepositoryFragment(): Fragment() { class EditRepositoryFragment(): ScreenFragment() {
companion object { companion object {
private const val EXTRA_REPOSITORY_ID = "repositoryId" private const val EXTRA_REPOSITORY_ID = "repositoryId"
@@ -95,8 +94,8 @@ class EditRepositoryFragment(): Fragment() {
syncConnection.bind(requireContext()) syncConnection.bind(requireContext())
val toolbar = view.findViewById<Toolbar>(R.id.toolbar) val toolbar = view.findViewById<Toolbar>(R.id.toolbar)!!
screenActivity.onFragmentViewCreated(toolbar) screenActivity.onToolbarCreated(toolbar)
if (repositoryId != null) { if (repositoryId != null) {
toolbar.setTitle(R.string.edit_repository) toolbar.setTitle(R.string.edit_repository)
} else { } else {
@@ -114,7 +113,7 @@ class EditRepositoryFragment(): Fragment() {
} }
} }
val content = view.findViewById<FrameLayout>(R.id.fragment_content) val content = view.findViewById<FrameLayout>(R.id.fragment_content)!!
errorColorFilter = PorterDuffColorFilter(content.context errorColorFilter = PorterDuffColorFilter(content.context
.getColorFromAttr(R.attr.colorError).defaultColor, PorterDuff.Mode.SRC_IN) .getColorFromAttr(R.attr.colorError).defaultColor, PorterDuff.Mode.SRC_IN)
@@ -24,7 +24,7 @@ import nya.kitsunyan.foxydroid.R
import nya.kitsunyan.foxydroid.content.Preferences import nya.kitsunyan.foxydroid.content.Preferences
import nya.kitsunyan.foxydroid.utility.extension.resources.* import nya.kitsunyan.foxydroid.utility.extension.resources.*
class PreferencesFragment: Fragment() { class PreferencesFragment: ScreenFragment() {
private val preferences = mutableMapOf<Preferences.Key<*>, Preference<*>>() private val preferences = mutableMapOf<Preferences.Key<*>, Preference<*>>()
private var disposable: Disposable? = null private var disposable: Disposable? = null
@@ -35,11 +35,11 @@ class PreferencesFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val toolbar = view.findViewById<Toolbar>(R.id.toolbar) val toolbar = view.findViewById<Toolbar>(R.id.toolbar)!!
screenActivity.onFragmentViewCreated(toolbar) screenActivity.onToolbarCreated(toolbar)
toolbar.setTitle(R.string.preferences) toolbar.setTitle(R.string.preferences)
val content = view.findViewById<FrameLayout>(R.id.fragment_content) val content = view.findViewById<FrameLayout>(R.id.fragment_content)!!
val scroll = ScrollView(content.context) val scroll = ScrollView(content.context)
scroll.id = R.id.preferences_list scroll.id = R.id.preferences_list
scroll.isFillViewport = true scroll.isFillViewport = true
@@ -13,7 +13,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.Toolbar import android.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@@ -35,7 +34,7 @@ import nya.kitsunyan.foxydroid.utility.RxUtils
import nya.kitsunyan.foxydroid.utility.Utils import nya.kitsunyan.foxydroid.utility.Utils
import nya.kitsunyan.foxydroid.widget.DividerItemDecoration import nya.kitsunyan.foxydroid.widget.DividerItemDecoration
class ProductFragment(): Fragment(), ProductAdapter.Callbacks { class ProductFragment(): ScreenFragment(), ProductAdapter.Callbacks {
companion object { companion object {
private const val EXTRA_PACKAGE_NAME = "packageName" private const val EXTRA_PACKAGE_NAME = "packageName"
@@ -87,8 +86,8 @@ class ProductFragment(): Fragment(), ProductAdapter.Callbacks {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val toolbar = view.findViewById<Toolbar>(R.id.toolbar) val toolbar = view.findViewById<Toolbar>(R.id.toolbar)!!
screenActivity.onFragmentViewCreated(toolbar) screenActivity.onToolbarCreated(toolbar)
toolbar.setTitle(R.string.application) toolbar.setTitle(R.string.application)
this.toolbar = toolbar this.toolbar = toolbar
@@ -105,7 +104,7 @@ class ProductFragment(): Fragment(), ProductAdapter.Callbacks {
} }
} }
val content = view.findViewById<FrameLayout>(R.id.fragment_content) val content = view.findViewById<FrameLayout>(R.id.fragment_content)!!
content.addView(RecyclerView(content.context).apply { content.addView(RecyclerView(content.context).apply {
id = android.R.id.list id = android.R.id.list
val columns = (resources.configuration.screenWidthDp / 120).coerceIn(3, 5) val columns = (resources.configuration.screenWidthDp / 120).coerceIn(3, 5)
@@ -6,7 +6,6 @@ import android.os.Parcelable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@@ -22,7 +21,7 @@ import nya.kitsunyan.foxydroid.utility.extension.resources.*
import nya.kitsunyan.foxydroid.widget.DividerItemDecoration import nya.kitsunyan.foxydroid.widget.DividerItemDecoration
import nya.kitsunyan.foxydroid.widget.RecyclerFastScroller import nya.kitsunyan.foxydroid.widget.RecyclerFastScroller
class ProductsFragment(): Fragment(), CursorOwner.Callback { class ProductsFragment(): ScreenFragment(), CursorOwner.Callback {
companion object { companion object {
private const val EXTRA_SOURCE = "source" private const val EXTRA_SOURCE = "source"
@@ -8,7 +8,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.Toolbar import android.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import nya.kitsunyan.foxydroid.R import nya.kitsunyan.foxydroid.R
@@ -17,14 +16,14 @@ import nya.kitsunyan.foxydroid.service.Connection
import nya.kitsunyan.foxydroid.service.SyncService import nya.kitsunyan.foxydroid.service.SyncService
import nya.kitsunyan.foxydroid.utility.Utils import nya.kitsunyan.foxydroid.utility.Utils
class RepositoriesFragment: Fragment(), CursorOwner.Callback { class RepositoriesFragment: ScreenFragment(), CursorOwner.Callback {
private var recyclerView: RecyclerView? = null private var recyclerView: RecyclerView? = null
private val syncConnection = Connection(SyncService::class.java) private val syncConnection = Connection(SyncService::class.java)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment, container, false).apply { return inflater.inflate(R.layout.fragment, container, false).apply {
val content = findViewById<FrameLayout>(R.id.fragment_content) val content = findViewById<FrameLayout>(R.id.fragment_content)!!
content.addView(RecyclerView(content.context).apply { content.addView(RecyclerView(content.context).apply {
id = android.R.id.list id = android.R.id.list
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
@@ -44,8 +43,8 @@ class RepositoriesFragment: Fragment(), CursorOwner.Callback {
syncConnection.bind(requireContext()) syncConnection.bind(requireContext())
screenActivity.cursorOwner.attach(this, CursorOwner.Request.Repositories) screenActivity.cursorOwner.attach(this, CursorOwner.Request.Repositories)
val toolbar = view.findViewById<Toolbar>(R.id.toolbar) val toolbar = view.findViewById<Toolbar>(R.id.toolbar)!!
screenActivity.onFragmentViewCreated(toolbar) screenActivity.onToolbarCreated(toolbar)
toolbar.setTitle(R.string.repositories) toolbar.setTitle(R.string.repositories)
toolbar.menu.apply { toolbar.menu.apply {
@@ -14,7 +14,6 @@ import android.widget.LinearLayout
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.TextView import android.widget.TextView
import android.widget.Toolbar import android.widget.Toolbar
import androidx.fragment.app.Fragment
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
@@ -27,7 +26,7 @@ import nya.kitsunyan.foxydroid.utility.extension.resources.*
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
class RepositoryFragment(): Fragment() { class RepositoryFragment(): ScreenFragment() {
companion object { companion object {
private const val EXTRA_REPOSITORY_ID = "repositoryId" private const val EXTRA_REPOSITORY_ID = "repositoryId"
} }
@@ -59,8 +58,8 @@ class RepositoryFragment(): Fragment() {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe { updateRepositoryView() } .subscribe { updateRepositoryView() }
val toolbar = view.findViewById<Toolbar>(R.id.toolbar) val toolbar = view.findViewById<Toolbar>(R.id.toolbar)!!
screenActivity.onFragmentViewCreated(toolbar) screenActivity.onToolbarCreated(toolbar)
toolbar.setTitle(R.string.repository) toolbar.setTitle(R.string.repository)
toolbar.menu.apply { toolbar.menu.apply {
@@ -81,7 +80,7 @@ class RepositoryFragment(): Fragment() {
} }
} }
val content = view.findViewById<FrameLayout>(R.id.fragment_content) val content = view.findViewById<FrameLayout>(R.id.fragment_content)!!
val scroll = ScrollView(content.context) val scroll = ScrollView(content.context)
scroll.id = android.R.id.list scroll.id = android.R.id.list
scroll.isFillViewport = true scroll.isFillViewport = true
@@ -151,9 +150,9 @@ class RepositoryFragment(): Fragment() {
private fun LinearLayout.addTitleText(titleResId: Int, text: CharSequence) { private fun LinearLayout.addTitleText(titleResId: Int, text: CharSequence) {
if (text.isNotEmpty()) { if (text.isNotEmpty()) {
val layout = inflate(R.layout.title_text_item) val layout = inflate(R.layout.title_text_item)
val titleView = layout.findViewById<TextView>(R.id.title) val titleView = layout.findViewById<TextView>(R.id.title)!!
titleView.setText(titleResId) titleView.setText(titleResId)
val textView = layout.findViewById<TextView>(R.id.text) val textView = layout.findViewById<TextView>(R.id.text)!!
textView.text = text textView.text = text
addView(layout) addView(layout)
} }
@@ -21,7 +21,6 @@ import nya.kitsunyan.foxydroid.utility.Utils
import nya.kitsunyan.foxydroid.utility.extension.android.* import nya.kitsunyan.foxydroid.utility.extension.android.*
import nya.kitsunyan.foxydroid.utility.extension.resources.* import nya.kitsunyan.foxydroid.utility.extension.resources.*
import nya.kitsunyan.foxydroid.utility.extension.text.* import nya.kitsunyan.foxydroid.utility.extension.text.*
import java.lang.ref.WeakReference
abstract class ScreenActivity: FragmentActivity() { abstract class ScreenActivity: FragmentActivity() {
companion object { companion object {
@@ -58,7 +57,6 @@ abstract class ScreenActivity: FragmentActivity() {
private set private set
private val fragmentStack = mutableListOf<FragmentStackItem>() private val fragmentStack = mutableListOf<FragmentStackItem>()
private var toolbar: WeakReference<Toolbar>? = null
private val currentFragment: Fragment? private val currentFragment: Fragment?
get() { get() {
@@ -105,10 +103,8 @@ abstract class ScreenActivity: FragmentActivity() {
} }
override fun onBackPressed() { override fun onBackPressed() {
val menuItem = toolbar?.get()?.menu?.findItem(R.id.toolbar_search) val currentFragment = currentFragment
if (menuItem != null && menuItem.isActionViewExpanded) { if (!(currentFragment is ScreenFragment && currentFragment.onBackPressed())) {
menuItem.collapseActionView()
} else {
hideKeyboard() hideKeyboard()
if (!popFragment()) { if (!popFragment()) {
super.onBackPressed() super.onBackPressed()
@@ -159,9 +155,8 @@ abstract class ScreenActivity: FragmentActivity() {
hideKeyboard() hideKeyboard()
} }
internal fun onFragmentViewCreated(toolbar: Toolbar?) { internal fun onToolbarCreated(toolbar: Toolbar) {
this.toolbar = toolbar?.let(::WeakReference) if (fragmentStack.isNotEmpty()) {
if (fragmentStack.isNotEmpty() && toolbar != null) {
toolbar.navigationIcon = toolbar.context.getDrawableFromAttr(android.R.attr.homeAsUpIndicator) toolbar.navigationIcon = toolbar.context.getDrawableFromAttr(android.R.attr.homeAsUpIndicator)
toolbar.setNavigationOnClickListener { onBackPressed() } toolbar.setNavigationOnClickListener { onBackPressed() }
} }
@@ -0,0 +1,10 @@
package nya.kitsunyan.foxydroid.screen
import androidx.fragment.app.Fragment
open class ScreenFragment: Fragment() {
val screenActivity: ScreenActivity
get() = requireActivity() as ScreenActivity
open fun onBackPressed(): Boolean = false
}
@@ -44,7 +44,7 @@ import nya.kitsunyan.foxydroid.utility.extension.text.*
import nya.kitsunyan.foxydroid.widget.EnumRecyclerAdapter import nya.kitsunyan.foxydroid.widget.EnumRecyclerAdapter
import kotlin.math.* import kotlin.math.*
class TabsFragment: Fragment() { class TabsFragment: ScreenFragment() {
companion object { companion object {
private const val STATE_SEARCH_QUERY = "searchQuery" private const val STATE_SEARCH_QUERY = "searchQuery"
private const val STATE_SHOW_CATEGORIES = "showCategories" private const val STATE_SHOW_CATEGORIES = "showCategories"
@@ -61,6 +61,7 @@ class TabsFragment: Fragment() {
val categoryIcon = view.findViewById<ImageView>(R.id.category_icon)!! val categoryIcon = view.findViewById<ImageView>(R.id.category_icon)!!
} }
private var searchMenuItem: MenuItem? = null
private var sortOrderMenu: Pair<MenuItem, List<MenuItem>>? = null private var sortOrderMenu: Pair<MenuItem, List<MenuItem>>? = null
private var syncRepositoriesMenuItem: MenuItem? = null private var syncRepositoriesMenuItem: MenuItem? = null
private var layout: Layout? = null private var layout: Layout? = null
@@ -111,8 +112,8 @@ class TabsFragment: Fragment() {
syncConnection.bind(requireContext()) syncConnection.bind(requireContext())
val toolbar = view.findViewById<Toolbar>(R.id.toolbar) val toolbar = view.findViewById<Toolbar>(R.id.toolbar)!!
screenActivity.onFragmentViewCreated(toolbar) screenActivity.onToolbarCreated(toolbar)
toolbar.setTitle(R.string.app_name) toolbar.setTitle(R.string.app_name)
val searchView = SearchView(toolbar.context) val searchView = SearchView(toolbar.context)
@@ -137,7 +138,7 @@ class TabsFragment: Fragment() {
setGroupDividerEnabled(true) setGroupDividerEnabled(true)
} }
add(0, R.id.toolbar_search, 0, R.string.search) searchMenuItem = add(0, R.id.toolbar_search, 0, R.string.search)
.setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_search)) .setIcon(Utils.getToolbarIcon(toolbar.context, R.drawable.ic_search))
.setActionView(searchView) .setActionView(searchView)
.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS or MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS or MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW)
@@ -183,7 +184,7 @@ class TabsFragment: Fragment() {
searchQuery = savedInstanceState?.getString(STATE_SEARCH_QUERY).orEmpty() searchQuery = savedInstanceState?.getString(STATE_SEARCH_QUERY).orEmpty()
productFragments.forEach { it.setSearchQuery(searchQuery) } productFragments.forEach { it.setSearchQuery(searchQuery) }
val toolbarExtra = view.findViewById<FrameLayout>(R.id.toolbar_extra) val toolbarExtra = view.findViewById<FrameLayout>(R.id.toolbar_extra)!!
toolbarExtra.addView(toolbarExtra.inflate(R.layout.tabs_toolbar)) toolbarExtra.addView(toolbarExtra.inflate(R.layout.tabs_toolbar))
val layout = Layout(view) val layout = Layout(view)
this.layout = layout this.layout = layout
@@ -219,7 +220,7 @@ class TabsFragment: Fragment() {
sortOrderMenu!!.second[order.ordinal].isChecked = true sortOrderMenu!!.second[order.ordinal].isChecked = true
productFragments.forEach { it.setOrder(order) } productFragments.forEach { it.setOrder(order) }
val content = view.findViewById<FrameLayout>(R.id.fragment_content) val content = view.findViewById<FrameLayout>(R.id.fragment_content)!!
viewPager = ViewPager2(content.context).apply { viewPager = ViewPager2(content.context).apply {
id = R.id.fragment_pager id = R.id.fragment_pager
@@ -289,6 +290,7 @@ class TabsFragment: Fragment() {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
searchMenuItem = null
sortOrderMenu = null sortOrderMenu = null
syncRepositoriesMenuItem = null syncRepositoriesMenuItem = null
layout = null layout = null
@@ -331,6 +333,22 @@ class TabsFragment: Fragment() {
} }
} }
override fun onBackPressed(): Boolean {
return when {
searchMenuItem?.isActionViewExpanded == true -> {
searchMenuItem?.collapseActionView()
true
}
showCategories -> {
showCategories = false
true
}
else -> {
super.onBackPressed()
}
}
}
private fun setSelectedTab(source: ProductsFragment.Source) { private fun setSelectedTab(source: ProductsFragment.Source) {
val layout = layout!! val layout = layout!!
(0 until layout.tabs.childCount).forEach { layout.tabs.getChildAt(it).isSelected = it == source.ordinal } (0 until layout.tabs.childCount).forEach { layout.tabs.getChildAt(it).isSelected = it == source.ordinal }