Different list modes

This commit is contained in:
Admin
2020-02-01 12:29:38 +02:00
parent 2bc19afea3
commit 05b0d34c1f
26 changed files with 508 additions and 42 deletions

View File

@@ -8,6 +8,7 @@ import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import org.koin.dsl.module
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.domain.MangaLoaderContext
import java.util.concurrent.TimeUnit
@@ -35,6 +36,10 @@ class KotatsuApp : Application() {
single {
mangaDb().build()
}
}, module {
factory {
AppSettings(applicationContext)
}
}
))
}

View File

@@ -0,0 +1,25 @@
package org.koitharu.kotatsu.core.prefs
import android.content.Context
import android.content.SharedPreferences
import android.content.res.Resources
import androidx.core.content.edit
import androidx.lifecycle.LifecycleOwner
import androidx.preference.PreferenceManager
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.utils.delegates.prefs.EnumPreferenceDelegate
class AppSettings private constructor(private val resources: Resources, private val prefs: SharedPreferences) : SharedPreferences by prefs {
constructor(context: Context) : this(context.resources, PreferenceManager.getDefaultSharedPreferences(context))
var listMode by EnumPreferenceDelegate(ListMode::class.java, resources.getString(R.string.key_list_mode), ListMode.LIST)
fun subscribe(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
prefs.registerOnSharedPreferenceChangeListener(listener)
}
fun unsubscribe(listener: SharedPreferences.OnSharedPreferenceChangeListener) {
prefs.unregisterOnSharedPreferenceChangeListener(listener)
}
}

View File

@@ -0,0 +1,13 @@
package org.koitharu.kotatsu.core.prefs
enum class ListMode(val id: Int) {
LIST(0),
DETAILED_LIST(1),
GRID(2);
companion object {
fun valueOf(id: Int) = values().firstOrNull { it.id == id }
}
}

View File

@@ -1,17 +1,24 @@
package org.koitharu.kotatsu.ui.common
import android.content.SharedPreferences
import android.os.Parcelable
import androidx.annotation.IdRes
import androidx.annotation.LayoutRes
import androidx.recyclerview.widget.RecyclerView
import moxy.MvpAppCompatFragment
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.utils.delegates.ParcelableArgumentDelegate
import org.koitharu.kotatsu.utils.delegates.StringArgumentDelegate
abstract class BaseFragment(@LayoutRes contentLayoutId: Int) :
MvpAppCompatFragment(contentLayoutId) {
MvpAppCompatFragment(contentLayoutId), SharedPreferences.OnSharedPreferenceChangeListener {
protected val settings by inject<AppSettings>()
fun stringArg(name: String) = StringArgumentDelegate(name)
fun <T : Parcelable> arg(name: String) = ParcelableArgumentDelegate<T>(name)
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) = Unit
}

View File

@@ -2,41 +2,54 @@ package org.koitharu.kotatsu.ui.common.widgets
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.content.res.use
import moxy.MvpFacade.init
import org.koitharu.kotatsu.R
class CoverImageView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatImageView(context, attrs, defStyleAttr) {
private var orientation: Int = HORIZONTAL
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val widthMode = MeasureSpec.getMode(widthMeasureSpec)
val heightMode = MeasureSpec.getMode(heightMeasureSpec)
if (widthMode == MeasureSpec.UNSPECIFIED) {
val originalWidth = MeasureSpec.getSize(widthMeasureSpec)
super.onMeasure(
MeasureSpec.makeMeasureSpec(originalWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(
(originalWidth * ASPECT_RATIO_HEIGHT / ASPECT_RATIO_WIDTH).toInt(),
MeasureSpec.EXACTLY
)
)
} else {
val originalHeight = MeasureSpec.getSize(heightMeasureSpec)
super.onMeasure(
MeasureSpec.makeMeasureSpec(
(originalHeight * ASPECT_RATIO_WIDTH / ASPECT_RATIO_HEIGHT).toInt(),
MeasureSpec.EXACTLY
),
MeasureSpec.makeMeasureSpec(originalHeight, MeasureSpec.EXACTLY)
)
}
}
init {
context.theme.obtainStyledAttributes(attrs, R.styleable.CoverImageView, defStyleAttr, 0)
.use {
orientation = it.getInt(R.styleable.CoverImageView_android_orientation, HORIZONTAL)
}
}
private companion object {
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
if (orientation == VERTICAL) {
val originalHeight = MeasureSpec.getSize(heightMeasureSpec)
super.onMeasure(
MeasureSpec.makeMeasureSpec(
(originalHeight * ASPECT_RATIO_WIDTH / ASPECT_RATIO_HEIGHT).toInt(),
MeasureSpec.EXACTLY
),
MeasureSpec.makeMeasureSpec(originalHeight, MeasureSpec.EXACTLY)
)
} else {
val originalWidth = MeasureSpec.getSize(widthMeasureSpec)
super.onMeasure(
MeasureSpec.makeMeasureSpec(originalWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(
(originalWidth * ASPECT_RATIO_HEIGHT / ASPECT_RATIO_WIDTH).toInt(),
MeasureSpec.EXACTLY
)
)
}
}
const val ASPECT_RATIO_HEIGHT = 18f
const val ASPECT_RATIO_WIDTH = 13f
}
companion object {
const val VERTICAL = LinearLayout.VERTICAL
const val HORIZONTAL = LinearLayout.HORIZONTAL
private const val ASPECT_RATIO_HEIGHT = 18f
private const val ASPECT_RATIO_WIDTH = 13f
}
}

View File

@@ -0,0 +1,64 @@
package org.koitharu.kotatsu.ui.main.list
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import kotlinx.android.synthetic.main.dialog_list_mode.*
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.ListMode
class ListModeSelectDialog : DialogFragment(), View.OnClickListener {
private val setting by inject<AppSettings>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.dialog_list_mode, container, false)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
setTitle(R.string.list_mode)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val mode = setting.listMode
button_list.isChecked = mode == ListMode.LIST
button_list_detailed.isChecked = mode == ListMode.DETAILED_LIST
button_grid.isChecked = mode == ListMode.GRID
button_ok.setOnClickListener(this)
button_list.setOnClickListener(this)
button_grid.setOnClickListener(this)
button_list_detailed.setOnClickListener(this)
}
override fun onClick(v: View) {
when (v.id) {
R.id.button_ok -> dismiss()
R.id.button_list -> setting.listMode = ListMode.LIST
R.id.button_list_detailed -> setting.listMode = ListMode.DETAILED_LIST
R.id.button_grid -> setting.listMode = ListMode.GRID
}
}
companion object {
private const val TAG = "LIST_MODE"
fun show(fm: FragmentManager) = ListModeSelectDialog().show(fm, TAG)
}
}

View File

@@ -2,12 +2,19 @@ package org.koitharu.kotatsu.ui.main.list
import android.view.ViewGroup
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter
class MangaListAdapter(onItemClickListener: ((Manga) -> Unit)?) :
BaseRecyclerAdapter<Manga>(onItemClickListener) {
override fun onCreateViewHolder(parent: ViewGroup) = MangaListHolder(parent)
var listMode: ListMode = ListMode.LIST
override fun onCreateViewHolder(parent: ViewGroup) = when(listMode) {
ListMode.LIST -> MangaListHolder(parent)
ListMode.DETAILED_LIST -> MangaListDetailsHolder(parent)
ListMode.GRID -> MangaGridHolder(parent)
}
override fun onGetItemId(item: Manga) = item.id
}

View File

@@ -0,0 +1,24 @@
package org.koitharu.kotatsu.ui.main.list
import android.view.ViewGroup
import coil.api.load
import coil.request.RequestDisposable
import kotlinx.android.synthetic.main.item_manga_list_details.*
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.ui.common.list.BaseViewHolder
import org.koitharu.kotatsu.utils.ext.textAndVisible
class MangaListDetailsHolder(parent: ViewGroup) : BaseViewHolder<Manga>(parent, R.layout.item_manga_list_details) {
private var coverRequest: RequestDisposable? = null
override fun onBind(data: Manga) {
coverRequest?.dispose()
textView_title.text = data.title
textView_subtitle.textAndVisible = data.localizedTitle
coverRequest = imageView_cover.load(data.coverUrl) {
crossfade(true)
}
}
}

View File

@@ -1,9 +1,15 @@
package org.koitharu.kotatsu.ui.main.list
import android.content.SharedPreferences
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_list.*
@@ -11,13 +17,12 @@ import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.prefs.ListMode
import org.koitharu.kotatsu.ui.common.BaseFragment
import org.koitharu.kotatsu.ui.common.list.PaginationScrollListener
import org.koitharu.kotatsu.ui.common.list.SpacingItemDecoration
import org.koitharu.kotatsu.ui.main.details.MangaDetailsActivity
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import org.koitharu.kotatsu.utils.ext.hasItems
import org.koitharu.kotatsu.utils.ext.withArgs
import org.koitharu.kotatsu.utils.ext.*
class MangaListFragment : BaseFragment(R.layout.fragment_list), MangaListView,
PaginationScrollListener.Callback {
@@ -28,18 +33,28 @@ class MangaListFragment : BaseFragment(R.layout.fragment_list), MangaListView,
private lateinit var adapter: MangaListAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
adapter = MangaListAdapter {
startActivity(MangaDetailsActivity.newIntent(context ?: return@MangaListAdapter, it))
}
// recyclerView.addItemDecoration(SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing)))
recyclerView.addItemDecoration(DividerItemDecoration(view.context, RecyclerView.VERTICAL))
initListMode(settings.listMode)
recyclerView.adapter = adapter
recyclerView.addOnScrollListener(PaginationScrollListener(4, this))
swipeRefreshLayout.setOnRefreshListener {
presenter.loadList(source, 0)
}
settings.subscribe(this)
}
override fun onDestroyView() {
settings.unsubscribe(this)
super.onDestroyView()
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
@@ -47,6 +62,19 @@ class MangaListFragment : BaseFragment(R.layout.fragment_list), MangaListView,
presenter.loadList(source, 0)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.opt_list, menu)
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem) = when(item.itemId) {
R.id.action_list_mode -> {
ListModeSelectDialog.show(childFragmentManager)
true
}
else -> super.onOptionsItemSelected(item)
}
override fun onRequestMoreItems(offset: Int) {
presenter.loadList(source, offset)
}
@@ -72,6 +100,33 @@ class MangaListFragment : BaseFragment(R.layout.fragment_list), MangaListView,
swipeRefreshLayout.isEnabled = !progressBar.isVisible
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
when(key) {
getString(R.string.key_list_mode) -> initListMode(settings.listMode)
}
}
private fun initListMode(mode: ListMode) {
val ctx = context ?: return
val position = recyclerView.firstItem
recyclerView.adapter = null
recyclerView.layoutManager = null
recyclerView.clearItemDecorations()
adapter.listMode = mode
recyclerView.layoutManager = when(mode) {
ListMode.GRID -> GridLayoutManager(ctx, 3)
else -> LinearLayoutManager(ctx)
}
recyclerView.adapter = adapter
recyclerView.addItemDecoration(when(mode) {
ListMode.DETAILED_LIST,
ListMode.LIST -> DividerItemDecoration(ctx, RecyclerView.VERTICAL)
ListMode.GRID -> SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing))
})
adapter.notifyDataSetChanged()
recyclerView.firstItem = position
}
companion object {
private const val ARG_SOURCE = "provider"

View File

@@ -0,0 +1,28 @@
package org.koitharu.kotatsu.utils.delegates.prefs
import android.content.SharedPreferences
import androidx.core.content.edit
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class EnumPreferenceDelegate<E : Enum<*>>(
private val cls: Class<E>,
private val key: String,
private val defValue: E
) :
ReadWriteProperty<SharedPreferences, E> {
override fun getValue(thisRef: SharedPreferences, property: KProperty<*>): E {
val ord = thisRef.getInt(key, -1)
if (ord == -1) {
return defValue
}
return cls.enumConstants?.firstOrNull { it.ordinal == ord } ?: defValue
}
override fun setValue(thisRef: SharedPreferences, property: KProperty<*>, value: E) {
thisRef.edit {
putInt(key, value.ordinal)
}
}
}

View File

@@ -0,0 +1,19 @@
package org.koitharu.kotatsu.utils.delegates.prefs
import android.content.SharedPreferences
import androidx.core.content.edit
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class NullableStringPreferenceDelegate(private val key: String) : ReadWriteProperty<SharedPreferences, String?> {
override fun getValue(thisRef: SharedPreferences, property: KProperty<*>): String? {
return thisRef.getString(key, null)
}
override fun setValue(thisRef: SharedPreferences, property: KProperty<*>, value: String?) {
thisRef.edit {
putString(key, value)
}
}
}

View File

@@ -0,0 +1,20 @@
package org.koitharu.kotatsu.utils.delegates.prefs
import android.content.SharedPreferences
import androidx.core.content.edit
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class StringPreferenceDelegate(private val key: String, private val defValue: String) :
ReadWriteProperty<SharedPreferences, String> {
override fun getValue(thisRef: SharedPreferences, property: KProperty<*>): String {
return thisRef.getString(key, defValue) ?: defValue
}
override fun setValue(thisRef: SharedPreferences, property: KProperty<*>, value: String) {
thisRef.edit {
putString(key, value)
}
}
}

View File

@@ -12,9 +12,11 @@ import androidx.annotation.LayoutRes
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import kotlinx.android.synthetic.main.fragment_list.view.*
import org.koitharu.kotatsu.ui.common.ChipsFactory
fun View.hideKeyboard() {
@@ -73,4 +75,19 @@ fun <T> ChipGroup.setChips(data: Iterable<T>, action: ChipsFactory.(T) -> Chip)
val chip = factory.action(it)
addView(chip)
}
}
}
fun RecyclerView.clearItemDecorations() {
while (itemDecorationCount > 0) {
removeItemDecorationAt(0)
}
}
var RecyclerView.firstItem: Int
get() = (layoutManager as? LinearLayoutManager)?.findFirstVisibleItemPosition()
?: RecyclerView.NO_POSITION
set(value) {
if (value != RecyclerView.NO_POSITION) {
(layoutManager as? LinearLayoutManager)?.scrollToPositionWithOffset(value, 0)
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M3,11H11V3H3M3,21H11V13H3M13,21H21V13H13M13,3V11H21V3" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M3,4H7V8H3V4M9,5V7H21V5H9M3,10H7V14H3V10M9,11V13H21V11H9M3,16H7V20H3V16M9,17V19H21V17H9" />
</vector>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M2 14H8V20H2M16 8H10V10H16M2 10H8V4H2M10 4V6H22V4M10 20H16V18H10M10 16H22V14H10" />
</vector>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="vertical">
<com.google.android.material.button.MaterialButtonToggleGroup
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:selectionRequired="true"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="@+id/button_list"
style="@style/AppToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/list"
app:icon="@drawable/ic_list" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_list_detailed"
style="@style/AppToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/detailed_list"
app:icon="@drawable/ic_list_detailed" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_grid"
style="@style/AppToggleButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/grid"
app:icon="@drawable/ic_grid" />
</com.google.android.material.button.MaterialButtonToggleGroup>
<com.google.android.material.button.MaterialButton
android:id="@+id/button_ok"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_gravity="center_horizontal"
android:text="@android:string/ok" />
</LinearLayout>

View File

@@ -8,6 +8,7 @@
<org.koitharu.kotatsu.ui.common.widgets.CoverImageView
android:id="@+id/imageView_cover"
android:layout_width="wrap_content"
android:orientation="vertical"
android:layout_height="match_parent" />
<LinearLayout

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/manga_list_details_item_height"
android:background="?selectableItemBackground"
android:orientation="horizontal">
<org.koitharu.kotatsu.ui.common.widgets.CoverImageView
android:id="@+id/imageView_cover"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:orientation="vertical"
android:paddingTop="12dp"
android:paddingStart="16dp"
android:paddingEnd="16dp">
<TextView
android:id="@+id/textView_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="2"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1" />
<TextView
android:id="@+id/textView_subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:lines="1"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
android:textColor="?android:textColorSecondary" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_list_mode"
android:title="@string/list_mode"
android:orderInCategory="20"
app:showAsAction="never" />
</menu>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CoverImageView">
<attr name="android:orientation" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="key_list_mode">list_mode</string>
</resources>

View File

@@ -2,5 +2,6 @@
<resources>
<dimen name="grid_spacing">5dp</dimen>
<dimen name="manga_list_item_height">84dp</dimen>
<dimen name="manga_list_details_item_height">120dp</dimen>
<dimen name="chapter_list_item_height">46dp</dimen>
</resources>

View File

@@ -9,4 +9,8 @@
<string name="network_error">Network connection error</string>
<string name="details">Details</string>
<string name="chapters">Chapters</string>
<string name="list">List</string>
<string name="detailed_list">Detailed list</string>
<string name="grid">Grid</string>
<string name="list_mode">List mode</string>
</resources>

View File

@@ -1,10 +1,11 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<style name="AppToggleButton" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="android:checkable">true</item>
<item name="android:gravity">center_vertical|start</item>
<item name="iconPadding">16dp</item>
<item name="android:paddingTop">10dp</item>
<item name="android:paddingBottom">10dp</item>
</style>
</resources>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>