Optimize layout for tablet

This commit is contained in:
Koitharu
2020-02-29 12:47:03 +02:00
parent 5f49030926
commit ad201d2bcd
16 changed files with 412 additions and 41 deletions

View File

@@ -1,17 +1,27 @@
package org.koitharu.kotatsu.ui.common
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.appcompat.app.AppCompatDialog
import moxy.MvpBottomSheetDialogFragment
import org.koitharu.kotatsu.utils.UiUtils
abstract class BaseBottomSheet(@LayoutRes private val layoutResId: Int) : MvpBottomSheetDialogFragment() {
abstract class BaseBottomSheet(@LayoutRes private val layoutResId: Int) :
MvpBottomSheetDialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(layoutResId, container, false)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return if (UiUtils.isTablet(requireContext())) {
AppCompatDialog(context, theme)
} else super.onCreateDialog(savedInstanceState)
}
}

View File

@@ -14,6 +14,7 @@ import org.koitharu.kotatsu.ui.common.BaseFragment
import org.koitharu.kotatsu.ui.main.list.favourites.categories.FavouriteCategoriesDialog
import org.koitharu.kotatsu.ui.reader.ReaderActivity
import org.koitharu.kotatsu.utils.ext.setChips
import org.koitharu.kotatsu.utils.ext.textAndVisible
import kotlin.math.roundToInt
class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetailsView {
@@ -31,7 +32,7 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
crossfade(true)
}
textView_title.text = manga.title
textView_subtitle.text = manga.altTitle
textView_subtitle.textAndVisible = manga.altTitle
textView_description.text = manga.description?.parseAsHtml()?.takeUnless(Spanned::isBlank)
?: getString(R.string.no_description)
if (manga.rating == Manga.NO_RATING) {

View File

@@ -51,7 +51,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
drawer?.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
adapter = MangaListAdapter(this)
initListMode(settings.listMode)
recyclerView.adapter = adapter
@@ -88,15 +88,15 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
true
}
R.id.action_filter -> {
drawer.toggleDrawer(GravityCompat.END)
drawer?.toggleDrawer(GravityCompat.END)
true
}
else -> super.onOptionsItemSelected(item)
}
override fun onPrepareOptionsMenu(menu: Menu) {
menu.findItem(R.id.action_filter).isVisible =
drawer.getDrawerLockMode(GravityCompat.END) != DrawerLayout.LOCK_MODE_LOCKED_CLOSED
menu.findItem(R.id.action_filter).isVisible = drawer != null &&
drawer?.getDrawerLockMode(GravityCompat.END) != DrawerLayout.LOCK_MODE_LOCKED_CLOSED
super.onPrepareOptionsMenu(menu)
}
@@ -184,7 +184,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
currentFilter: MangaFilter?
) {
recyclerView_filter.adapter = FilterAdapter(sortOrders, tags, currentFilter, this)
drawer.setDrawerLockMode(
drawer?.setDrawerLockMode(
if (sortOrders.isEmpty() && tags.isEmpty()) {
DrawerLayout.LOCK_MODE_LOCKED_CLOSED
} else {
@@ -196,7 +196,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
@CallSuper
override fun onFilterChanged(filter: MangaFilter) {
drawer.closeDrawers()
drawer?.closeDrawers()
}
protected open fun setUpEmptyListHolder() {
@@ -210,6 +210,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
recyclerView.adapter = null
recyclerView.layoutManager = null
recyclerView.clearItemDecorations()
recyclerView.removeOnLayoutChangeListener(UiUtils.SpanCountResolver)
adapter?.listMode = mode
recyclerView.layoutManager = when (mode) {
ListMode.GRID -> GridLayoutManager(ctx, UiUtils.resolveGridSpanCount(ctx))
@@ -225,6 +226,9 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
)
}
)
if(mode == ListMode.GRID) {
recyclerView.addOnLayoutChangeListener(UiUtils.SpanCountResolver)
}
adapter?.notifyDataSetChanged()
recyclerView.firstItem = position
}

View File

@@ -4,7 +4,6 @@ import android.os.Bundle
import android.view.View
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.android.synthetic.main.sheet_pages.*
@@ -33,17 +32,22 @@ class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages),
dismissAllowingStateLoss()
return
}
(recyclerView.layoutManager as? GridLayoutManager)?.spanCount = UiUtils.resolveGridSpanCount(view.context)
val title = arguments?.getString(ARG_TITLE)
toolbar.title = title
toolbar.setNavigationOnClickListener { dismiss() }
toolbar.subtitle = resources.getQuantityString(R.plurals.pages, pages.size, pages.size)
textView_title.text = title
if (dialog !is BottomSheetDialog) {
toolbar.isVisible = true
textView_title.isVisible = false
appbar.elevation = resources.getDimension(R.dimen.elevation_large)
}
recyclerView.addOnLayoutChangeListener(UiUtils.SpanCountResolver)
}
override fun onCreateDialog(savedInstanceState: Bundle?) =
super.onCreateDialog(savedInstanceState).also {
val behavior = (it as BottomSheetDialog).behavior
val behavior = (it as? BottomSheetDialog)?.behavior ?: return@also
behavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
private val elevation = resources.getDimension(R.dimen.elevation_large)
@@ -52,15 +56,16 @@ class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages),
override fun onStateChanged(bottomSheet: View, newState: Int) {
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
toolbar.isVisible = true
textView_title.isVisible = false
appbar.elevation = elevation
} else {
toolbar.isVisible = false
textView_title.isVisible = true
appbar.elevation = 0f
}
}
})
// behavior.peekHeight = BottomSheetBehavior.PEEK_HEIGHT_AUTO
// behavior.isFitToContents = false
}
override fun onDestroyView() {

View File

@@ -3,22 +3,62 @@ package org.koitharu.kotatsu.ui.settings
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.commit
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import kotlinx.android.synthetic.main.activity_settings.*
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.ui.common.BaseActivity
class SettingsActivity : BaseActivity() {
class SettingsActivity : BaseActivity(),
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_settings)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
val isTablet = container_side != null
if (supportFragmentManager.findFragmentById(R.id.container) == null) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, SettingsHeadersFragment())
.commit()
supportFragmentManager.commit {
if (isTablet) {
replace(R.id.container_side, SettingsHeadersFragment())
replace(R.id.container, AppearanceSettingsFragment())
} else {
replace(R.id.container, SettingsHeadersFragment())
}
}
}
}
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean {
val fm = supportFragmentManager
if (container_side != null && caller is SettingsHeadersFragment) {
fm.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
val fragment = fm.fragmentFactory.instantiate(classLoader, pref.fragment)
fragment.arguments = pref.extras
fragment.setTargetFragment(caller, 0)
fm.commit {
replace(R.id.container, fragment)
if (container_side == null || caller !is SettingsHeadersFragment) {
addToBackStack(null)
}
}
return true
}
override fun onTitleChanged(title: CharSequence?, color: Int) {
if (container_side == null) {
super.onTitleChanged(title, color)
} else {
if (supportFragmentManager.backStackEntryCount == 0) {
supportActionBar?.subtitle = null
} else {
supportActionBar?.subtitle = title
}
}
}

View File

@@ -9,4 +9,5 @@ class SettingsHeadersFragment : BasePreferenceFragment(R.string.settings) {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_headers)
}
}

View File

@@ -2,8 +2,12 @@ package org.koitharu.kotatsu.utils
import android.content.Context
import android.graphics.Color
import android.view.View
import androidx.annotation.ColorInt
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import org.koitharu.kotatsu.R
import kotlin.math.abs
import kotlin.math.roundToInt
object UiUtils {
@@ -19,10 +23,31 @@ object UiUtils {
}
@JvmStatic
fun resolveGridSpanCount(context: Context): Int {
fun resolveGridSpanCount(context: Context, width: Int = 0): Int {
val cellWidth = context.resources.getDimensionPixelSize(R.dimen.preferred_grid_width)
val screenWidth = context.resources.displayMetrics.widthPixels.toDouble()
val screenWidth = (if (width <= 0) {
context.resources.displayMetrics.widthPixels
} else width).toDouble()
val estimatedCount = (screenWidth / cellWidth).roundToInt()
return estimatedCount.coerceAtLeast(2)
}
@JvmStatic
fun isTablet(context: Context) = context.resources.getBoolean(R.bool.is_tablet)
object SpanCountResolver : View.OnLayoutChangeListener {
override fun onLayoutChange(
v: View?, left: Int, top: Int, right: Int, bottom: Int,
oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int
) {
val rv = v as? RecyclerView ?: return
val width = abs(right - left)
if (width == 0) {
return
}
(rv.layoutManager as? GridLayoutManager)?.spanCount =
resolveGridSpanCount(rv.context, width)
}
}
}