Merge branch 'feature/m3' into devel

pull/124/head
Koitharu 4 years ago
commit 8a08d58ed7
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -12,18 +12,20 @@ import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.ActionBarContextView import androidx.appcompat.widget.ActionBarContextView
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.graphics.Insets import androidx.core.view.ViewCompat
import androidx.core.view.* import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.LayoutParams.*
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
abstract class BaseActivity<B : ViewBinding> : AppCompatActivity(), OnApplyWindowInsetsListener { abstract class BaseActivity<B : ViewBinding> : AppCompatActivity(),
WindowInsetsDelegate.WindowInsetsListener {
protected lateinit var binding: B protected lateinit var binding: B
private set private set
@ -31,7 +33,8 @@ abstract class BaseActivity<B : ViewBinding> : AppCompatActivity(), OnApplyWindo
@Suppress("LeakingThis") @Suppress("LeakingThis")
protected val exceptionResolver = ExceptionResolver(this) protected val exceptionResolver = ExceptionResolver(this)
private var lastInsets: Insets? = null @Suppress("LeakingThis")
protected val insetsDelegate = WindowInsetsDelegate(this)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
val settings = get<AppSettings>() val settings = get<AppSettings>()
@ -41,6 +44,7 @@ abstract class BaseActivity<B : ViewBinding> : AppCompatActivity(), OnApplyWindo
} }
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
insetsDelegate.handleImeInsets = true
} }
@Deprecated("Use ViewBinding", level = DeprecationLevel.ERROR) @Deprecated("Use ViewBinding", level = DeprecationLevel.ERROR)
@ -60,28 +64,7 @@ abstract class BaseActivity<B : ViewBinding> : AppCompatActivity(), OnApplyWindo
super.setContentView(binding.root) super.setContentView(binding.root)
val toolbar = (binding.root.findViewById<View>(R.id.toolbar) as? Toolbar) val toolbar = (binding.root.findViewById<View>(R.id.toolbar) as? Toolbar)
toolbar?.let(this::setSupportActionBar) toolbar?.let(this::setSupportActionBar)
ViewCompat.setOnApplyWindowInsetsListener(binding.root, this) insetsDelegate.onViewCreated(binding.root)
val toolbarParams = (binding.root.findViewById<View>(R.id.toolbar_card) ?: toolbar)
?.layoutParams as? AppBarLayout.LayoutParams
if (toolbarParams != null) {
if (get<AppSettings>().isToolbarHideWhenScrolling) {
toolbarParams.scrollFlags = SCROLL_FLAG_SCROLL or SCROLL_FLAG_ENTER_ALWAYS or SCROLL_FLAG_SNAP
} else {
toolbarParams.scrollFlags = SCROLL_FLAG_NO_SCROLL
}
}
}
override fun onApplyWindowInsets(v: View, insets: WindowInsetsCompat): WindowInsetsCompat {
val baseInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime())
val newInsets = Insets.max(baseInsets, imeInsets)
if (newInsets != lastInsets) {
onWindowInsetsChanged(newInsets)
lastInsets = newInsets
}
return insets
} }
override fun onOptionsItemSelected(item: MenuItem) = if (item.itemId == android.R.id.home) { override fun onOptionsItemSelected(item: MenuItem) = if (item.itemId == android.R.id.home) {
@ -97,8 +80,6 @@ abstract class BaseActivity<B : ViewBinding> : AppCompatActivity(), OnApplyWindo
return super.onKeyDown(keyCode, event) return super.onKeyDown(keyCode, event)
} }
protected abstract fun onWindowInsetsChanged(insets: Insets)
private fun setupToolbar() { private fun setupToolbar() {
(findViewById<View>(R.id.toolbar) as? Toolbar)?.let(this::setSupportActionBar) (findViewById<View>(R.id.toolbar) as? Toolbar)?.let(this::setSupportActionBar)
} }

@ -4,16 +4,13 @@ import android.os.Bundle
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.core.graphics.Insets
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.doOnNextLayout
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
abstract class BaseFragment<B : ViewBinding> : Fragment(), OnApplyWindowInsetsListener { abstract class BaseFragment<B : ViewBinding> : Fragment(),
WindowInsetsDelegate.WindowInsetsListener {
private var viewBinding: B? = null private var viewBinding: B? = null
@ -23,7 +20,8 @@ abstract class BaseFragment<B : ViewBinding> : Fragment(), OnApplyWindowInsetsLi
@Suppress("LeakingThis") @Suppress("LeakingThis")
protected val exceptionResolver = ExceptionResolver(this) protected val exceptionResolver = ExceptionResolver(this)
private var lastInsets: Insets? = null @Suppress("LeakingThis")
protected val insetsDelegate = WindowInsetsDelegate(this)
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -37,33 +35,16 @@ abstract class BaseFragment<B : ViewBinding> : Fragment(), OnApplyWindowInsetsLi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
ViewCompat.setOnApplyWindowInsetsListener(view, this) insetsDelegate.onViewCreated(view)
view.doOnNextLayout {
// Listener may not be called
if (lastInsets == null) {
onWindowInsetsChanged(Insets.NONE)
}
}
} }
override fun onDestroyView() { override fun onDestroyView() {
viewBinding = null viewBinding = null
lastInsets = null insetsDelegate.onDestroyView()
super.onDestroyView() super.onDestroyView()
} }
override fun onApplyWindowInsets(v: View?, insets: WindowInsetsCompat): WindowInsetsCompat {
val newInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
if (newInsets != lastInsets) {
onWindowInsetsChanged(newInsets)
lastInsets = newInsets
}
return insets
}
protected fun bindingOrNull() = viewBinding protected fun bindingOrNull() = viewBinding
protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B
protected abstract fun onWindowInsetsChanged(insets: Insets)
} }

@ -2,38 +2,53 @@ package org.koitharu.kotatsu.base.ui
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.annotation.CallSuper
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.view.OnApplyWindowInsetsListener import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.recyclerview.widget.RecyclerView
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.base.ui.util.WindowInsetsDelegate
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : PreferenceFragmentCompat(), abstract class BasePreferenceFragment(@StringRes private val titleId: Int) : PreferenceFragmentCompat(),
OnApplyWindowInsetsListener { WindowInsetsDelegate.WindowInsetsListener,
RecyclerViewOwner {
protected val settings by inject<AppSettings>(mode = LazyThreadSafetyMode.NONE) protected val settings by inject<AppSettings>(mode = LazyThreadSafetyMode.NONE)
@Suppress("LeakingThis")
protected val insetsDelegate = WindowInsetsDelegate(this)
override val recyclerView: RecyclerView
get() = listView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
listView.clipToPadding = false listView.clipToPadding = false
ViewCompat.setOnApplyWindowInsetsListener(view, this) insetsDelegate.onViewCreated(view)
}
override fun onDestroyView() {
insetsDelegate.onDestroyView()
super.onDestroyView()
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (titleId != 0) {
activity?.setTitle(titleId) activity?.setTitle(titleId)
} }
}
override fun onApplyWindowInsets(v: View?, insets: WindowInsetsCompat): WindowInsetsCompat { @CallSuper
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) override fun onWindowInsetsChanged(insets: Insets) {
listView.updatePadding( listView.updatePadding(
left = systemBars.left, left = insets.left,
right = systemBars.right, right = insets.right,
bottom = systemBars.bottom bottom = insets.bottom
) )
return insets
} }
} }

@ -0,0 +1,8 @@
package org.koitharu.kotatsu.base.ui.util
import androidx.recyclerview.widget.RecyclerView
interface RecyclerViewOwner {
val recyclerView: RecyclerView
}

@ -0,0 +1,69 @@
package org.koitharu.kotatsu.base.ui.util
import android.view.View
import androidx.core.graphics.Insets
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
class WindowInsetsDelegate(
private val listener: WindowInsetsListener,
) : OnApplyWindowInsetsListener, View.OnLayoutChangeListener {
var handleImeInsets: Boolean = false
var interceptingWindowInsetsListener: OnApplyWindowInsetsListener? = null
private var lastInsets: Insets? = null
override fun onApplyWindowInsets(v: View?, insets: WindowInsetsCompat?): WindowInsetsCompat? {
if (insets == null) {
return null
}
val handledInsets = interceptingWindowInsetsListener?.onApplyWindowInsets(v, insets) ?: insets
val newInsets = if (handleImeInsets) {
Insets.max(
handledInsets.getInsets(WindowInsetsCompat.Type.systemBars()),
handledInsets.getInsets(WindowInsetsCompat.Type.ime()),
)
} else {
handledInsets.getInsets(WindowInsetsCompat.Type.systemBars())
}
if (newInsets != lastInsets) {
listener.onWindowInsetsChanged(newInsets)
lastInsets = newInsets
}
return handledInsets
}
override fun onLayoutChange(
view: View,
left: Int,
top: Int,
right: Int,
bottom: Int,
oldLeft: Int,
oldTop: Int,
oldRight: Int,
oldBottom: Int,
) {
view.removeOnLayoutChangeListener(this)
if (lastInsets == null) { // Listener may not be called
onApplyWindowInsets(view, ViewCompat.getRootWindowInsets(view))
}
}
fun onViewCreated(view: View) {
ViewCompat.setOnApplyWindowInsetsListener(view, this)
view.addOnLayoutChangeListener(this)
}
fun onDestroyView() {
lastInsets = null
}
interface WindowInsetsListener {
fun onWindowInsetsChanged(insets: Insets)
}
}

@ -0,0 +1,120 @@
package org.koitharu.kotatsu.base.ui.widgets
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.TypedArray
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.RippleDrawable
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.RectShape
import android.util.AttributeSet
import androidx.annotation.AttrRes
import androidx.appcompat.widget.AppCompatCheckedTextView
import androidx.core.content.res.use
import androidx.core.content.withStyledAttributes
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
import org.koitharu.kotatsu.R
class ListItemTextView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int = R.attr.listItemTextViewStyle,
) : AppCompatCheckedTextView(context, attrs, defStyleAttr) {
private var checkedDrawableStart: Drawable? = null
private var checkedDrawableEnd: Drawable? = null
private var isInitialized = false
private var isCheckDrawablesVisible: Boolean = false
private var defaultPaddingStart: Int = 0
private var defaultPaddingEnd: Int = 0
init {
context.withStyledAttributes(attrs, R.styleable.ListItemTextView, defStyleAttr) {
background = RippleDrawable(
getColorStateList(R.styleable.ListItemTextView_rippleColor) ?: getRippleColorFallback(context),
createShapeDrawable(this),
ShapeDrawable(RectShape()),
)
checkedDrawableStart = getDrawable(R.styleable.ListItemTextView_checkedDrawableStart)
checkedDrawableEnd = getDrawable(R.styleable.ListItemTextView_checkedDrawableEnd)
}
checkedDrawableStart?.setTintList(textColors)
checkedDrawableEnd?.setTintList(textColors)
defaultPaddingStart = paddingStart
defaultPaddingEnd = paddingEnd
isInitialized = true
adjustCheckDrawables()
}
override fun refreshDrawableState() {
super.refreshDrawableState()
adjustCheckDrawables()
}
override fun setTextColor(colors: ColorStateList?) {
checkedDrawableStart?.setTintList(colors)
checkedDrawableEnd?.setTintList(colors)
super.setTextColor(colors)
}
override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
defaultPaddingStart = start
defaultPaddingEnd = end
super.setPaddingRelative(start, top, end, bottom)
}
override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
defaultPaddingStart = if (isRtl) right else left
defaultPaddingEnd = if (isRtl) left else right
super.setPadding(left, top, right, bottom)
}
private fun adjustCheckDrawables() {
if (isInitialized && isCheckDrawablesVisible != isChecked) {
setCompoundDrawablesRelativeWithIntrinsicBounds(
if (isChecked) checkedDrawableStart else null,
null,
if (isChecked) checkedDrawableEnd else null,
null,
)
super.setPaddingRelative(
if (isChecked && checkedDrawableStart != null) {
defaultPaddingStart + compoundDrawablePadding
} else defaultPaddingStart,
paddingTop,
if (isChecked && checkedDrawableEnd != null) {
defaultPaddingEnd + compoundDrawablePadding
} else defaultPaddingEnd,
paddingBottom,
)
isCheckDrawablesVisible = isChecked
}
}
private fun createShapeDrawable(ta: TypedArray): InsetDrawable {
val shapeAppearance = ShapeAppearanceModel.builder(
context,
ta.getResourceId(R.styleable.ListItemTextView_shapeAppearance, 0),
ta.getResourceId(R.styleable.ListItemTextView_shapeAppearanceOverlay, 0),
).build()
val shapeDrawable = MaterialShapeDrawable(shapeAppearance)
shapeDrawable.fillColor = ta.getColorStateList(R.styleable.ListItemTextView_backgroundTint)
return InsetDrawable(
shapeDrawable,
ta.getDimensionPixelOffset(R.styleable.ListItemTextView_android_insetLeft, 0),
ta.getDimensionPixelOffset(R.styleable.ListItemTextView_android_insetTop, 0),
ta.getDimensionPixelOffset(R.styleable.ListItemTextView_android_insetRight, 0),
ta.getDimensionPixelOffset(R.styleable.ListItemTextView_android_insetBottom, 0),
)
}
private fun getRippleColorFallback(context: Context): ColorStateList {
return context.obtainStyledAttributes(intArrayOf(android.R.attr.colorControlHighlight)).use {
it.getColorStateList(0)
} ?: ColorStateList.valueOf(Color.TRANSPARENT)
}
}

@ -45,9 +45,6 @@ class AppSettings(context: Context) {
val isAmoledTheme: Boolean val isAmoledTheme: Boolean
get() = prefs.getBoolean(KEY_THEME_AMOLED, false) get() = prefs.getBoolean(KEY_THEME_AMOLED, false)
val isToolbarHideWhenScrolling: Boolean
get() = prefs.getBoolean(KEY_HIDE_TOOLBAR, true)
var gridSize: Int var gridSize: Int
get() = prefs.getInt(KEY_GRID_SIZE, 100) get() = prefs.getInt(KEY_GRID_SIZE, 100)
set(value) = prefs.edit { putInt(KEY_GRID_SIZE, value) } set(value) = prefs.edit { putInt(KEY_GRID_SIZE, value) }
@ -215,7 +212,6 @@ class AppSettings(context: Context) {
const val KEY_DYNAMIC_THEME = "dynamic_theme" const val KEY_DYNAMIC_THEME = "dynamic_theme"
const val KEY_THEME_AMOLED = "amoled_theme" const val KEY_THEME_AMOLED = "amoled_theme"
const val KEY_DATE_FORMAT = "date_format" const val KEY_DATE_FORMAT = "date_format"
const val KEY_HIDE_TOOLBAR = "hide_toolbar"
const val KEY_SOURCES_ORDER = "sources_order" const val KEY_SOURCES_ORDER = "sources_order"
const val KEY_SOURCES_HIDDEN = "sources_hidden" const val KEY_SOURCES_HIDDEN = "sources_hidden"
const val KEY_TRAFFIC_WARNING = "traffic_warning" const val KEY_TRAFFIC_WARNING = "traffic_warning"

@ -53,7 +53,6 @@ class ChaptersFragment : BaseFragment<FragmentChaptersBinding>(),
chaptersAdapter = ChaptersAdapter(this) chaptersAdapter = ChaptersAdapter(this)
selectionDecoration = ChaptersSelectionDecoration(view.context) selectionDecoration = ChaptersSelectionDecoration(view.context)
with(binding.recyclerViewChapters) { with(binding.recyclerViewChapters) {
addItemDecoration(MaterialDividerItemDecoration(view.context, RecyclerView.VERTICAL))
addItemDecoration(selectionDecoration!!) addItemDecoration(selectionDecoration!!)
setHasFixedSize(true) setHasFixedSize(true)
adapter = chaptersAdapter adapter = chaptersAdapter

@ -47,15 +47,10 @@ class DownloadsActivity : BaseActivity<ActivityDownloadsBinding>() {
right = insets.right, right = insets.right,
bottom = insets.bottom bottom = insets.bottom
) )
with(binding.toolbar) { binding.toolbar.updatePadding(
updatePadding(
left = insets.left, left = insets.left,
right = insets.right right = insets.right
) )
updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top
}
}
} }
companion object { companion object {

@ -12,7 +12,6 @@ import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.divider.MaterialDividerItemDecoration
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@ -42,7 +41,6 @@ class CategoriesActivity : BaseActivity<ActivityCategoriesBinding>(),
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
adapter = CategoriesAdapter(this) adapter = CategoriesAdapter(this)
editDelegate = CategoriesEditDelegate(this, this) editDelegate = CategoriesEditDelegate(this, this)
binding.recyclerView.addItemDecoration(MaterialDividerItemDecoration(this, RecyclerView.VERTICAL))
binding.recyclerView.setHasFixedSize(true) binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.adapter = adapter binding.recyclerView.adapter = adapter
binding.fabAdd.setOnClickListener(this) binding.fabAdd.setOnClickListener(this)
@ -94,15 +92,6 @@ class CategoriesActivity : BaseActivity<ActivityCategoriesBinding>(),
right = insets.right, right = insets.right,
bottom = 2 * insets.bottom + binding.fabAdd.measureHeight() bottom = 2 * insets.bottom + binding.fabAdd.measureHeight()
) )
with(binding.toolbar) {
updatePadding(
left = insets.left,
right = insets.right
)
updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top
}
}
} }
private fun onCategoriesChanged(categories: List<FavouriteCategory>) { private fun onCategoriesChanged(categories: List<FavouriteCategory>) {

@ -6,14 +6,13 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.ui.titleRes import org.koitharu.kotatsu.core.ui.titleRes
import org.koitharu.kotatsu.databinding.ItemCheckableMultipleBinding import org.koitharu.kotatsu.databinding.ItemCheckableNewBinding
import org.koitharu.kotatsu.databinding.ItemCheckableSingleBinding
import org.koitharu.kotatsu.databinding.ItemFilterHeaderBinding import org.koitharu.kotatsu.databinding.ItemFilterHeaderBinding
fun filterSortDelegate( fun filterSortDelegate(
listener: OnFilterChangedListener, listener: OnFilterChangedListener,
) = adapterDelegateViewBinding<FilterItem.Sort, FilterItem, ItemCheckableSingleBinding>( ) = adapterDelegateViewBinding<FilterItem.Sort, FilterItem, ItemCheckableNewBinding>(
{ layoutInflater, parent -> ItemCheckableSingleBinding.inflate(layoutInflater, parent, false) } { layoutInflater, parent -> ItemCheckableNewBinding.inflate(layoutInflater, parent, false) }
) { ) {
itemView.setOnClickListener { itemView.setOnClickListener {
@ -28,8 +27,8 @@ fun filterSortDelegate(
fun filterTagDelegate( fun filterTagDelegate(
listener: OnFilterChangedListener, listener: OnFilterChangedListener,
) = adapterDelegateViewBinding<FilterItem.Tag, FilterItem, ItemCheckableMultipleBinding>( ) = adapterDelegateViewBinding<FilterItem.Tag, FilterItem, ItemCheckableNewBinding>(
{ layoutInflater, parent -> ItemCheckableMultipleBinding.inflate(layoutInflater, parent, false) } { layoutInflater, parent -> ItemCheckableNewBinding.inflate(layoutInflater, parent, false) }
) { ) {
itemView.setOnClickListener { itemView.setOnClickListener {

@ -13,10 +13,7 @@ import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.WindowInsetsCompat import androidx.core.view.*
import androidx.core.view.isVisible
import androidx.core.view.postDelayed
import androidx.core.view.updatePadding
import androidx.fragment.app.commit import androidx.fragment.app.commit
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.transition.Slide import androidx.transition.Slide
@ -60,7 +57,7 @@ import org.koitharu.kotatsu.utils.ext.observeWithPrevious
class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(), class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
ChaptersBottomSheet.OnChapterChangeListener, ChaptersBottomSheet.OnChapterChangeListener,
GridTouchHelper.OnGridTouchListener, OnPageSelectListener, ReaderConfigDialog.Callback, GridTouchHelper.OnGridTouchListener, OnPageSelectListener, ReaderConfigDialog.Callback,
ActivityResultCallback<Boolean>, ReaderControlDelegate.OnInteractionListener { ActivityResultCallback<Boolean>, ReaderControlDelegate.OnInteractionListener, OnApplyWindowInsetsListener {
private val viewModel by viewModel<ReaderViewModel> { private val viewModel by viewModel<ReaderViewModel> {
parametersOf(MangaIntent(intent), intent?.getParcelableExtra<ReaderState>(EXTRA_STATE)) parametersOf(MangaIntent(intent), intent?.getParcelableExtra<ReaderState>(EXTRA_STATE))
@ -87,6 +84,7 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
controlDelegate = ReaderControlDelegate(lifecycleScope, get(), this) controlDelegate = ReaderControlDelegate(lifecycleScope, get(), this)
binding.toolbarBottom.inflateMenu(R.menu.opt_reader_bottom) binding.toolbarBottom.inflateMenu(R.menu.opt_reader_bottom)
binding.toolbarBottom.setOnMenuItemClickListener(::onOptionsItemSelected) binding.toolbarBottom.setOnMenuItemClickListener(::onOptionsItemSelected)
insetsDelegate.interceptingWindowInsetsListener = this
orientationHelper.observeAutoOrientation() orientationHelper.observeAutoOrientation()
.onEach { .onEach {
@ -286,8 +284,6 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
viewModel.switchMode(mode) viewModel.switchMode(mode)
} }
override fun onWindowInsetsChanged(insets: Insets) = Unit
private fun onPageSaved(uri: Uri?) { private fun onPageSaved(uri: Uri?) {
if (uri != null) { if (uri != null) {
Snackbar.make(binding.container, R.string.page_saved, Snackbar.LENGTH_INDEFINITE) Snackbar.make(binding.container, R.string.page_saved, Snackbar.LENGTH_INDEFINITE)
@ -353,6 +349,8 @@ class ReaderActivity : BaseFullscreenActivity<ActivityReaderBinding>(),
.build() .build()
} }
override fun onWindowInsetsChanged(insets: Insets) = Unit
override fun switchPageBy(delta: Int) { override fun switchPageBy(delta: Int) {
reader?.switchPageBy(delta) reader?.switchPageBy(delta)
} }

@ -119,9 +119,6 @@ class MainSettingsFragment : BasePreferenceFragment(R.string.settings),
AppSettings.KEY_THEME_AMOLED -> { AppSettings.KEY_THEME_AMOLED -> {
findPreference<Preference>(key)?.setSummary(R.string.restart_required) findPreference<Preference>(key)?.setSummary(R.string.restart_required)
} }
AppSettings.KEY_HIDE_TOOLBAR -> {
findPreference<Preference>(key)?.setSummary(R.string.restart_required)
}
AppSettings.KEY_LOCAL_STORAGE -> { AppSettings.KEY_LOCAL_STORAGE -> {
findPreference<Preference>(key)?.bindStorageName() findPreference<Preference>(key)?.bindStorageName()
} }

@ -3,10 +3,7 @@ package org.koitharu.kotatsu.settings
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.ViewGroup
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
@ -15,8 +12,10 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseActivity import org.koitharu.kotatsu.base.ui.BaseActivity
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.databinding.ActivitySettingsBinding import org.koitharu.kotatsu.databinding.ActivitySettingsBinding
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.utils.ext.isScrolledToTop
class SettingsActivity : BaseActivity<ActivitySettingsBinding>(), class SettingsActivity : BaseActivity<ActivitySettingsBinding>(),
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback, PreferenceFragmentCompat.OnPreferenceStartFragmentCallback,
@ -34,6 +33,11 @@ class SettingsActivity : BaseActivity<ActivitySettingsBinding>(),
} }
} }
override fun onTitleChanged(title: CharSequence?, color: Int) {
super.onTitleChanged(title, color)
binding.collapsingToolbarLayout.title = title
}
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
supportFragmentManager.addOnBackStackChangedListener(this) supportFragmentManager.addOnBackStackChangedListener(this)
@ -45,7 +49,11 @@ class SettingsActivity : BaseActivity<ActivitySettingsBinding>(),
} }
override fun onBackStackChanged() { override fun onBackStackChanged() {
binding.appbar.setExpanded(true, true) val fragment = supportFragmentManager.findFragmentById(R.id.container) as? RecyclerViewOwner ?: return
val recyclerView = fragment.recyclerView
recyclerView.post {
binding.appbar.setExpanded(recyclerView.isScrolledToTop, false)
}
} }
override fun onPreferenceStartFragment( override fun onPreferenceStartFragment(
@ -77,17 +85,7 @@ class SettingsActivity : BaseActivity<ActivitySettingsBinding>(),
} }
} }
override fun onWindowInsetsChanged(insets: Insets) { override fun onWindowInsetsChanged(insets: Insets) = Unit
with(binding.toolbar) {
updatePadding(
left = insets.left,
right = insets.right
)
updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = insets.top
}
}
}
companion object { companion object {

@ -3,12 +3,12 @@ package org.koitharu.kotatsu.settings
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
@ -18,7 +18,7 @@ import org.koitharu.kotatsu.utils.ext.serializableArgument
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
class SourceSettingsFragment : PreferenceFragmentCompat() { class SourceSettingsFragment : BasePreferenceFragment(0) {
private val source by serializableArgument<MangaSource>(EXTRA_SOURCE) private val source by serializableArgument<MangaSource>(EXTRA_SOURCE)
private var repository: RemoteMangaRepository? = null private var repository: RemoteMangaRepository? = null

@ -11,19 +11,25 @@ import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.BaseFragment import org.koitharu.kotatsu.base.ui.BaseFragment
import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding
import org.koitharu.kotatsu.settings.SettingsActivity import org.koitharu.kotatsu.settings.SettingsActivity
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigAdapter import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigAdapter
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigItemDecoration
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(), class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(),
SourceConfigListener, SearchView.OnQueryTextListener, MenuItem.OnActionExpandListener { SourceConfigListener,
SearchView.OnQueryTextListener,
MenuItem.OnActionExpandListener,
RecyclerViewOwner {
private var reorderHelper: ItemTouchHelper? = null private var reorderHelper: ItemTouchHelper? = null
private val viewModel by viewModel<SourcesSettingsViewModel>() private val viewModel by viewModel<SourcesSettingsViewModel>()
override val recyclerView: RecyclerView
get() = binding.recyclerView
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setHasOptionsMenu(true) setHasOptionsMenu(true)
@ -44,7 +50,7 @@ class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(),
val sourcesAdapter = SourceConfigAdapter(this, get(), viewLifecycleOwner) val sourcesAdapter = SourceConfigAdapter(this, get(), viewLifecycleOwner)
with(binding.recyclerView) { with(binding.recyclerView) {
setHasFixedSize(true) setHasFixedSize(true)
addItemDecoration(SourceConfigItemDecoration(view.context)) // addItemDecoration(SourceConfigItemDecoration(view.context))
adapter = sourcesAdapter adapter = sourcesAdapter
reorderHelper = ItemTouchHelper(SourcesReorderCallback()).also { reorderHelper = ItemTouchHelper(SourcesReorderCallback()).also {
it.attachToRecyclerView(this) it.attachToRecyclerView(this)

@ -79,6 +79,7 @@ class SourcesSettingsViewModel(
} }
SourceConfigItem.SourceItem( SourceConfigItem.SourceItem(
source = it, source = it,
summary = null,
isEnabled = it.name !in hiddenSources, isEnabled = it.name !in hiddenSources,
isDraggable = false, isDraggable = false,
) )
@ -101,6 +102,7 @@ class SourcesSettingsViewModel(
enabledSources.mapTo(result) { enabledSources.mapTo(result) {
SourceConfigItem.SourceItem( SourceConfigItem.SourceItem(
source = it, source = it,
summary = getLocaleTitle(it.locale),
isEnabled = true, isEnabled = true,
isDraggable = true, isDraggable = true,
) )
@ -116,13 +118,14 @@ class SourcesSettingsViewModel(
val isExpanded = key in expandedGroups val isExpanded = key in expandedGroups
result += SourceConfigItem.LocaleGroup( result += SourceConfigItem.LocaleGroup(
localeId = key, localeId = key,
title = locale?.getDisplayLanguage(locale)?.toTitleCase(locale), title = getLocaleTitle(key),
isExpanded = isExpanded, isExpanded = isExpanded,
) )
if (isExpanded) { if (isExpanded) {
list.mapTo(result) { list.mapTo(result) {
SourceConfigItem.SourceItem( SourceConfigItem.SourceItem(
source = it, source = it,
summary = null,
isEnabled = false, isEnabled = false,
isDraggable = false, isDraggable = false,
) )
@ -133,6 +136,11 @@ class SourcesSettingsViewModel(
items.value = result items.value = result
} }
private fun getLocaleTitle(localeKey: String?): String? {
val locale = Locale(localeKey ?: return null)
return locale.getDisplayLanguage(locale).toTitleCase(locale)
}
private class LocaleKeyComparator : Comparator<String?> { private class LocaleKeyComparator : Comparator<String?> {
private val deviceLocales = LocaleListCompat.getAdjustedDefault() private val deviceLocales = LocaleListCompat.getAdjustedDefault()

@ -38,7 +38,7 @@ fun sourceConfigGroupDelegate(
} }
bind { bind {
binding.root.text = item.title ?: getString(R.string.other) binding.root.text = item.title ?: getString(R.string.various_languages)
binding.root.isChecked = item.isExpanded binding.root.isChecked = item.isExpanded
} }
} }
@ -107,6 +107,7 @@ fun sourceConfigDraggableItemDelegate(
bind { bind {
binding.textViewTitle.text = item.source.title binding.textViewTitle.text = item.source.title
binding.textViewDescription.text = item.summary ?: getString(R.string.various_languages)
binding.switchToggle.isChecked = item.isEnabled binding.switchToggle.isChecked = item.isEnabled
} }
} }

@ -50,6 +50,7 @@ sealed interface SourceConfigItem {
class SourceItem( class SourceItem(
val source: MangaSource, val source: MangaSource,
val isEnabled: Boolean, val isEnabled: Boolean,
val summary: String?,
val isDraggable: Boolean, val isDraggable: Boolean,
) : SourceConfigItem { ) : SourceConfigItem {
@ -63,6 +64,7 @@ sealed interface SourceConfigItem {
other as SourceItem other as SourceItem
if (source != other.source) return false if (source != other.source) return false
if (summary != other.summary) return false
if (isEnabled != other.isEnabled) return false if (isEnabled != other.isEnabled) return false
if (isDraggable != other.isDraggable) return false if (isDraggable != other.isDraggable) return false
@ -71,6 +73,7 @@ sealed interface SourceConfigItem {
override fun hashCode(): Int { override fun hashCode(): Int {
var result = source.hashCode() var result = source.hashCode()
result = 31 * result + summary.hashCode()
result = 31 * result + isEnabled.hashCode() result = 31 * result + isEnabled.hashCode()
result = 31 * result + isDraggable.hashCode() result = 31 * result + isDraggable.hashCode()
return result return result

@ -155,3 +155,12 @@ fun Slider.setValueRounded(newValue: Float) {
val step = stepSize val step = stepSize
value = (newValue / step).roundToInt() * step value = (newValue / step).roundToInt() * step
} }
val RecyclerView.isScrolledToTop: Boolean
get() {
if (childCount == 0) {
return true
}
val holder = findViewHolderForAdapterPosition(0)
return holder != null && holder.itemView.top >= 0
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="0.3" android:color="?attr/colorPrimary" android:state_checked="true"/>
<item android:color="@android:color/transparent"/>
</selector>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="@dimen/material_emphasis_disabled" android:color="?attr/colorOnSurfaceVariant" android:state_enabled="false" />
<item android:color="?attr/colorPrimaryDark" android:state_checked="true" />
<item android:color="?attr/colorOnSurfaceVariant" />
</selector>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorPrimaryContainer" android:state_checked="true" />
<item android:color="?colorSurfaceVariant" android:state_checked="false" />
</selector>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorPrimary" android:state_checked="true" />
<item android:color="?colorOnSurfaceVariant" android:state_checked="false" />
</selector>

@ -0,0 +1,11 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41L9,16.17z" />
</vector>

@ -1,5 +1,7 @@
<vector android:height="24dp" android:tint="#FFFFFF" <rotate
android:viewportHeight="24" android:viewportWidth="24" xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:drawable="@drawable/abc_ic_arrow_drop_right_black_24dp"
<path android:fillColor="@android:color/white" android:pathData="M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z"/> android:fromDegrees="-90"
</vector> android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-90" />

@ -1,11 +1,7 @@
<vector <rotate
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:drawable="@drawable/abc_ic_arrow_drop_right_black_24dp"
android:height="24dp" android:fromDegrees="90"
android:tint="#FFFFFF" android:pivotX="50%"
android:viewportWidth="24" android:pivotY="50%"
android:viewportHeight="24"> android:toDegrees="90" />
<path
android:fillColor="@android:color/white"
android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z" />
</vector>

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="4dp"
android:left="4dp"
android:right="4dp"
android:top="4dp">
<shape android:shape="oval">
<solid android:color="#000000" />
<size
android:width="20dp"
android:height="20dp" />
</shape>
</item>
</layer-list>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="#000000" />
<corners android:radius="56dp" />
<size
android:width="64dp"
android:height="28dp" />
</shape>
</item>
</layer-list>

@ -14,11 +14,21 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height_expanded"
app:toolbarId="@id/toolbar"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar" android:id="@id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways" /> app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

@ -31,9 +31,9 @@
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:elevation="0dp"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
app:elevation="0dp"
app:liftOnScroll="false"> app:liftOnScroll="false">
<FrameLayout <FrameLayout
@ -41,7 +41,9 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="54dp" android:layout_height="54dp"
android:layout_marginVertical="8dp" android:layout_marginVertical="8dp"
android:background="@drawable/toolbar_background"> android:background="@drawable/toolbar_background"
android:theme="@style/ThemeOverlay.Kotatsu.MainToolbar"
app:layout_scrollFlags="scroll|enterAlways">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar" android:id="@id/toolbar"

@ -69,11 +69,15 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
<androidx.constraintlayout.widget.Guideline <View
android:id="@+id/guideline" android:id="@+id/guideline"
android:layout_width="wrap_content" android:layout_width="1dp"
android:layout_height="wrap_content" android:layout_height="0dp"
android:orientation="vertical" android:background="?colorOutline"
app:layout_constraintGuide_percent="0.6" /> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.6"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appbar" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

@ -8,14 +8,24 @@
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar" android:id="@+id/appbar"
android:fitsSystemWindows="true"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height_expanded"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@id/toolbar">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar" android:id="@id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" /> app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

@ -10,14 +10,22 @@
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fitsSystemWindows="true" android:fitsSystemWindows="true">
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height_expanded"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@id/toolbar">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar" android:id="@id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"/> app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

@ -15,16 +15,16 @@
android:id="@id/container" android:id="@id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:layout="@layout/fragment_list" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> tools:layout="@layout/fragment_list" />
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@null"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
android:background="@null"
android:stateListAnimator="@null"> android:stateListAnimator="@null">
<FrameLayout <FrameLayout
@ -32,7 +32,9 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginVertical="8dp" android:layout_marginVertical="8dp"
android:background="@drawable/toolbar_background"> android:background="@drawable/toolbar_background"
android:theme="@style/ThemeOverlay.Kotatsu.MainToolbar"
app:layout_scrollFlags="scroll|enterAlways">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar" android:id="@id/toolbar"

@ -22,6 +22,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
app:iconifiedByDefault="false" app:iconifiedByDefault="false"
app:queryBackground="@null"
app:searchHintIcon="@null" app:searchHintIcon="@null"
app:searchIcon="@null" /> app:searchIcon="@null" />

@ -14,7 +14,7 @@
android:id="@id/toolbar" android:id="@id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" /> app:layout_scrollFlags="scroll|enterAlways" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

@ -8,14 +8,23 @@
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height_expanded"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
app:toolbarId="@id/toolbar">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar" android:id="@id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:theme="?attr/actionBarTheme" app:layout_collapseMode="pin" />
app:layout_scrollFlags="noScroll"/>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
@ -23,6 +32,6 @@
android:id="@id/container" android:id="@id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/> app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

@ -10,11 +10,19 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height_expanded"
app:toolbarId="@id/toolbar"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar" android:id="@id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="noScroll" /> app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>

@ -14,7 +14,7 @@
android:id="@+id/textView_number" android:id="@+id/textView_number"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="12dp" android:layout_marginStart="?android:listPreferredItemPaddingStart"
android:background="@drawable/bg_badge_default" android:background="@drawable/bg_badge_default"
android:gravity="center" android:gravity="center"
android:minWidth="26dp" android:minWidth="26dp"
@ -26,8 +26,8 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginVertical="8dp" android:layout_marginVertical="8dp"
android:layout_marginStart="16dp" android:layout_marginStart="?android:listPreferredItemPaddingStart"
android:layout_marginEnd="12dp" android:layout_marginEnd="?android:listPreferredItemPaddingEnd"
android:layout_weight="1" android:layout_weight="1"
android:orientation="vertical"> android:orientation="vertical">
@ -37,7 +37,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"
android:singleLine="true" android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodyMedium" android:textAppearance="?attr/textAppearanceBodyLarge"
tools:text="@tools:sample/lorem[15]" /> tools:text="@tools:sample/lorem[15]" />
<TextView <TextView
@ -46,6 +46,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="end" android:ellipsize="end"
android:singleLine="true" android:singleLine="true"
android:layout_marginTop="2dp"
android:textAppearance="?attr/textAppearanceBodySmall" android:textAppearance="?attr/textAppearanceBodySmall"
tools:text="05.10.2021 • Scanlator" /> tools:text="05.10.2021 • Scanlator" />
</LinearLayout> </LinearLayout>
@ -54,7 +55,7 @@
android:id="@+id/imageView_new" android:id="@+id/imageView_new"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="12dp" android:layout_marginEnd="?android:listPreferredItemPaddingEnd"
android:src="@drawable/ic_new" android:src="@drawable/ic_new"
app:tint="?colorError" /> app:tint="?colorError" />
@ -62,7 +63,7 @@
android:id="@+id/imageView_downloaded" android:id="@+id/imageView_downloaded"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="12dp" android:layout_marginEnd="?android:listPreferredItemPaddingEnd"
android:src="@drawable/ic_save_ok" /> android:src="@drawable/ic_save_ok" />
</LinearLayout> </LinearLayout>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<org.koitharu.kotatsu.base.ui.widgets.ListItemTextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?android:listPreferredItemHeightSmall"
android:drawablePadding="?android:listPreferredItemPaddingStart"
android:paddingStart="?android:listPreferredItemPaddingStart"
android:paddingEnd="?android:listPreferredItemPaddingEnd"
android:textAppearance="?attr/textAppearanceButton"
app:rippleColor="?colorSecondaryContainer"
tools:text="@tools:sample/full_names" />

@ -12,5 +12,5 @@
android:paddingEnd="?android:listPreferredItemPaddingEnd" android:paddingEnd="?android:listPreferredItemPaddingEnd"
android:textAppearance="?attr/textAppearanceBodyMedium" android:textAppearance="?attr/textAppearanceBodyMedium"
app:drawableEndCompat="@drawable/ic_expand_collapse" app:drawableEndCompat="@drawable/ic_expand_collapse"
app:drawableTint="?android:textColorPrimary" app:drawableTint="?android:colorControlNormal"
tools:text="@tools:sample/full_names" /> tools:text="@tools:sample/full_names" />

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -14,23 +14,20 @@
android:id="@+id/textView_title" android:id="@+id/textView_title"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:singleLine="true" android:singleLine="true"
android:textAppearance="@style/TextAppearance.Kotatsu.SectionHeader" android:textAppearance="@style/TextAppearance.Kotatsu.SectionHeader2"
tools:text="@tools:sample/lorem[2]" /> tools:text="@tools:sample/lorem[2]" />
<TextView <TextView
android:id="@+id/badge" android:id="@+id/badge"
style="?textAppearanceLabelSmall"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="12dp" android:layout_gravity="center_vertical|end"
android:background="@drawable/badge" android:singleLine="true"
android:paddingHorizontal="6dp"
android:paddingVertical="2dp"
android:textColor="?attr/colorOnTertiary"
android:textSize="12sp"
android:textStyle="bold"
android:visibility="gone" android:visibility="gone"
tools:text="54" tools:text="54"
tools:visibility="visible" /> tools:visibility="visible" />
</LinearLayout> </FrameLayout>

@ -3,9 +3,10 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?android:listPreferredItemHeightSmall" android:layout_height="wrap_content"
android:background="?android:windowBackground" android:background="?android:windowBackground"
android:gravity="center_vertical" android:gravity="center_vertical"
android:minHeight="58dp"
android:orientation="horizontal"> android:orientation="horizontal">
<ImageView <ImageView
@ -16,17 +17,35 @@
android:scaleType="center" android:scaleType="center"
android:src="@drawable/ic_reorder_handle" /> android:src="@drawable/ic_reorder_handle" />
<TextView <LinearLayout
android:id="@+id/textView_title"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:layout_marginStart="?android:listPreferredItemPaddingStart"
android:layout_marginEnd="?android:listPreferredItemPaddingEnd"
android:layout_weight="1" android:layout_weight="1"
android:ellipsize="marquee" android:orientation="vertical">
android:fadingEdge="horizontal"
<TextView
android:id="@+id/textView_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true" android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium" android:textAppearance="?attr/textAppearanceBodyLarge"
android:textColor="?android:attr/textColorPrimary" tools:text="@tools:sample/lorem[15]" />
tools:text="@tools:sample/lorem[1]" />
<TextView
android:id="@+id/textView_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="?attr/textAppearanceBodySmall"
tools:text="English" />
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial <com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_toggle" android:id="@+id/switch_toggle"

@ -37,6 +37,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:layout_marginEnd="4dp"
android:layout_weight="1" android:layout_weight="1"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="2" android:maxLines="2"
@ -61,7 +62,7 @@
<TextView <TextView
android:id="@+id/textView_chapters" android:id="@+id/textView_chapters"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:ellipsize="none" android:ellipsize="none"
android:lineSpacingExtra="4sp" android:lineSpacingExtra="4sp"

@ -27,7 +27,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:clipToPadding="false" android:clipToPadding="false"
android:orientation="vertical" android:orientation="vertical"
app:fastScrollEnabled="true"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/item_category_checkable" /> tools:listitem="@layout/item_checkable_new" />
</LinearLayout> </LinearLayout>

@ -2,6 +2,7 @@
<resources> <resources>
<attr name="sliderPreferenceStyle" /> <attr name="sliderPreferenceStyle" />
<attr name="listItemTextViewStyle" />
<declare-styleable name="Theme"> <declare-styleable name="Theme">
<attr name="navigationBarDividerColor" format="color" /> <attr name="navigationBarDividerColor" format="color" />
@ -20,4 +21,17 @@
<attr name="android:stepSize" /> <attr name="android:stepSize" />
</declare-styleable> </declare-styleable>
<declare-styleable name="ListItemTextView">
<attr name="shapeAppearance" />
<attr name="shapeAppearanceOverlay" />
<attr name="backgroundTint" />
<attr name="rippleColor" />
<attr name="checkedDrawableStart" format="reference" />
<attr name="checkedDrawableEnd" format="reference" />
<attr name="android:insetTop" />
<attr name="android:insetBottom" />
<attr name="android:insetLeft" />
<attr name="android:insetRight" />
</declare-styleable>
</resources> </resources>

@ -7,12 +7,13 @@
<!-- Navigation --> <!-- Navigation -->
<dimen name="nav_header_logo_size">36dp</dimen> <dimen name="nav_header_logo_size">36dp</dimen>
<dimen name="toolbar_height_expanded">172dp</dimen>
<dimen name="grid_spacing">8dp</dimen> <dimen name="grid_spacing">8dp</dimen>
<dimen name="list_spacing">8dp</dimen> <dimen name="list_spacing">8dp</dimen>
<dimen name="grid_spacing_outer">2dp</dimen> <dimen name="grid_spacing_outer">2dp</dimen>
<dimen name="manga_list_item_height">86dp</dimen> <dimen name="manga_list_item_height">86dp</dimen>
<dimen name="manga_list_details_item_height">120dp</dimen> <dimen name="manga_list_details_item_height">120dp</dimen>
<dimen name="chapter_list_item_height">56dp</dimen> <dimen name="chapter_list_item_height">62dp</dimen>
<dimen name="preferred_grid_width">120dp</dimen> <dimen name="preferred_grid_width">120dp</dimen>
<dimen name="header_height">48dp</dimen> <dimen name="header_height">48dp</dimen>
<dimen name="list_footer_height_inner">36dp</dimen> <dimen name="list_footer_height_inner">36dp</dimen>

@ -268,4 +268,5 @@
<string name="preload_pages">Preload pages</string> <string name="preload_pages">Preload pages</string>
<string name="logged_in_as">Logged in as %s</string> <string name="logged_in_as">Logged in as %s</string>
<string name="nsfw">18+</string> <string name="nsfw">18+</string>
<string name="various_languages">Various languages</string>
</resources> </resources>

@ -61,6 +61,10 @@
</style> </style>
<style name="Widget.Kotatsu.Switch" parent="Widget.Material3.CompoundButton.Switch"> <style name="Widget.Kotatsu.Switch" parent="Widget.Material3.CompoundButton.Switch">
<item name="android:thumb">@drawable/switch_thumb</item>
<item name="thumbTint">@color/selector_switch_thumb</item>
<item name="track">@drawable/switch_track</item>
<item name="trackTint">@color/selector_switch_track</item>
<item name="materialThemeOverlay">@style/ThemeOverlay.Kotatsu.Switch</item> <item name="materialThemeOverlay">@style/ThemeOverlay.Kotatsu.Switch</item>
</style> </style>
@ -72,6 +76,18 @@
<item name="android:scrollbarStyle">outsideOverlay</item> <item name="android:scrollbarStyle">outsideOverlay</item>
</style> </style>
<style name="Widget.Kotatsu.ListItemTextView" parent="">
<item name="android:textColor">@color/list_item_text_color</item>
<item name="backgroundTint">@color/list_item_background_color</item>
<item name="checkedDrawableStart">@drawable/ic_check</item>
<item name="shapeAppearanceOverlay">@style/ShapeAppearanceOverlay.Material3.NavigationView.Item</item>
<item name="android:gravity">center_vertical|start</item>
<item name="android:insetRight">6dp</item>
<item name="android:insetLeft">6dp</item>
<item name="android:insetTop">2dp</item>
<item name="android:insetBottom">2dp</item>
</style>
<style name="ThemeOverlay.Kotatsu.Switch" parent=""> <style name="ThemeOverlay.Kotatsu.Switch" parent="">
<item name="elevationOverlayEnabled">@bool/elevation_overlay_enabled</item> <item name="elevationOverlayEnabled">@bool/elevation_overlay_enabled</item>
</style> </style>
@ -98,6 +114,11 @@
<item name="android:textColor">?android:attr/textColorSecondary</item> <item name="android:textColor">?android:attr/textColorSecondary</item>
</style> </style>
<style name="TextAppearance.Kotatsu.SectionHeader2" parent="TextAppearance.Material3.LabelSmall">
<item name="android:textColor">?colorPrimary</item>
<item name="android:textAllCaps">true</item>
</style>
<!-- Shapes --> <!-- Shapes -->
<style name="ShapeAppearanceOverlay.Kotatsu.Cover" parent=""> <style name="ShapeAppearanceOverlay.Kotatsu.Cover" parent="">

@ -68,6 +68,7 @@
<item name="switchStyle">@style/Widget.Kotatsu.Switch</item> <item name="switchStyle">@style/Widget.Kotatsu.Switch</item>
<item name="materialCardViewStyle">@style/Widget.Material3.CardView.Filled</item> <item name="materialCardViewStyle">@style/Widget.Material3.CardView.Filled</item>
<item name="recyclerViewStyle">@style/Widget.Kotatsu.RecyclerView</item> <item name="recyclerViewStyle">@style/Widget.Kotatsu.RecyclerView</item>
<item name="listItemTextViewStyle">@style/Widget.Kotatsu.ListItemTextView</item>
<!-- Preference text appearance --> <!-- Preference text appearance -->
<item name="android:textAppearanceListItem">?attr/textAppearanceBodyLarge</item> <item name="android:textAppearanceListItem">?attr/textAppearanceBodyLarge</item>

@ -15,7 +15,7 @@
app:persistent="false" app:persistent="false"
app:summary="@string/check_for_updates" /> app:summary="@string/check_for_updates" />
<SwitchPreference <SwitchPreferenceCompat
app:defaultValue="true" app:defaultValue="true"
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:isPreferenceVisible="false" app:isPreferenceVisible="false"

@ -12,14 +12,14 @@
app:iconSpaceReserved="false" app:iconSpaceReserved="false"
app:useSimpleSummaryProvider="true" /> app:useSimpleSummaryProvider="true" />
<SwitchPreference <SwitchPreferenceCompat
android:defaultValue="false" android:defaultValue="false"
android:key="dynamic_theme" android:key="dynamic_theme"
android:summary="@string/dynamic_theme_summary" android:summary="@string/dynamic_theme_summary"
android:title="@string/dynamic_theme" android:title="@string/dynamic_theme"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<SwitchPreference <SwitchPreferenceCompat
android:defaultValue="false" android:defaultValue="false"
android:key="amoled_theme" android:key="amoled_theme"
android:summary="@string/black_dark_theme_summary" android:summary="@string/black_dark_theme_summary"
@ -31,12 +31,6 @@
android:title="@string/date_format" android:title="@string/date_format"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<SwitchPreferenceCompat
android:defaultValue="true"
android:key="hide_toolbar"
android:title="@string/hide_toolbar"
app:iconSpaceReserved="false" />
<ListPreference <ListPreference
android:entries="@array/list_modes" android:entries="@array/list_modes"
android:key="list_mode_2" android:key="list_mode_2"

@ -11,7 +11,7 @@
android:title="@string/track_sources" android:title="@string/track_sources"
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
<SwitchPreference <SwitchPreferenceCompat
android:defaultValue="true" android:defaultValue="true"
android:key="tracker_notifications" android:key="tracker_notifications"
android:summary="@string/show_notification_new_chapters" android:summary="@string/show_notification_new_chapters"

Loading…
Cancel
Save