Different list modes
parent
2bc19afea3
commit
05b0d34c1f
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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 }
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -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>
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="CoverImageView">
|
||||
<attr name="android:orientation" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="key_list_mode">list_mode</string>
|
||||
</resources>
|
||||
@ -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>
|
||||
@ -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>
|
||||
Loading…
Reference in New Issue