From 05b0d34c1fa305bdb5ffa8f0cdfaf589cbdcef20 Mon Sep 17 00:00:00 2001 From: Admin Date: Sat, 1 Feb 2020 12:29:38 +0200 Subject: [PATCH] Different list modes --- .../java/org/koitharu/kotatsu/KotatsuApp.kt | 5 ++ .../kotatsu/core/prefs/AppSettings.kt | 25 +++++++ .../koitharu/kotatsu/core/prefs/ListMode.kt | 13 ++++ .../kotatsu/ui/common/BaseFragment.kt | 9 ++- .../ui/common/widgets/CoverImageView.kt | 69 +++++++++++-------- .../ui/main/list/ListModeSelectDialog.kt | 64 +++++++++++++++++ .../kotatsu/ui/main/list/MangaListAdapter.kt | 9 ++- .../ui/main/list/MangaListDetailsHolder.kt | 24 +++++++ .../kotatsu/ui/main/list/MangaListFragment.kt | 65 +++++++++++++++-- .../delegates/prefs/EnumPreferenceDelegate.kt | 28 ++++++++ .../prefs/NullableStringPreferenceDelegate.kt | 19 +++++ .../prefs/StringPreferenceDelegate.kt | 20 ++++++ .../org/koitharu/kotatsu/utils/ext/ViewExt.kt | 19 ++++- app/src/main/res/drawable/ic_grid.xml | 12 ++++ app/src/main/res/drawable/ic_list.xml | 12 ++++ .../main/res/drawable/ic_list_detailed.xml | 12 ++++ app/src/main/res/layout/dialog_list_mode.xml | 51 ++++++++++++++ app/src/main/res/layout/item_manga_list.xml | 1 + .../res/layout/item_manga_list_details.xml | 43 ++++++++++++ app/src/main/res/menu/opt_list.xml | 11 +++ app/src/main/res/values/attrs.xml | 6 ++ app/src/main/res/values/constants.xml | 4 ++ app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 4 ++ app/src/main/res/values/styles.xml | 13 ++-- app/src/main/res/values/themes.xml | 11 +++ 26 files changed, 508 insertions(+), 42 deletions(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/core/prefs/ListMode.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/ui/main/list/ListModeSelectDialog.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListDetailsHolder.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/EnumPreferenceDelegate.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/NullableStringPreferenceDelegate.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/StringPreferenceDelegate.kt create mode 100644 app/src/main/res/drawable/ic_grid.xml create mode 100644 app/src/main/res/drawable/ic_list.xml create mode 100644 app/src/main/res/drawable/ic_list_detailed.xml create mode 100644 app/src/main/res/layout/dialog_list_mode.xml create mode 100644 app/src/main/res/layout/item_manga_list_details.xml create mode 100644 app/src/main/res/menu/opt_list.xml create mode 100644 app/src/main/res/values/attrs.xml create mode 100644 app/src/main/res/values/constants.xml create mode 100644 app/src/main/res/values/themes.xml diff --git a/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt b/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt index 432f8e5c1..22e24649b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt +++ b/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt @@ -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) + } } )) } diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt new file mode 100644 index 000000000..54c1f2a72 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -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) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/ListMode.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/ListMode.kt new file mode 100644 index 000000000..5934c49f8 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/ListMode.kt @@ -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 } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseFragment.kt index 48f160520..28c4b4d46 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/BaseFragment.kt @@ -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() fun stringArg(name: String) = StringArgumentDelegate(name) fun arg(name: String) = ParcelableArgumentDelegate(name) + + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) = Unit } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/CoverImageView.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/CoverImageView.kt index 894d4afc0..eacc89125 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/CoverImageView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/CoverImageView.kt @@ -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 + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/ListModeSelectDialog.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/ListModeSelectDialog.kt new file mode 100644 index 000000000..53aca3f66 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/ListModeSelectDialog.kt @@ -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() + + 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) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListAdapter.kt index d3b672c2f..1004b725e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListAdapter.kt @@ -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(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 } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListDetailsHolder.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListDetailsHolder.kt new file mode 100644 index 000000000..2cc84ff50 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListDetailsHolder.kt @@ -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(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) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt index 3e874a027..317897e98 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt @@ -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" diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/EnumPreferenceDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/EnumPreferenceDelegate.kt new file mode 100644 index 000000000..646c1db10 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/EnumPreferenceDelegate.kt @@ -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>( + private val cls: Class, + private val key: String, + private val defValue: E +) : + ReadWriteProperty { + + 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) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/NullableStringPreferenceDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/NullableStringPreferenceDelegate.kt new file mode 100644 index 000000000..e49dd1798 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/NullableStringPreferenceDelegate.kt @@ -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 { + + 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) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/StringPreferenceDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/StringPreferenceDelegate.kt new file mode 100644 index 000000000..775eda94d --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/delegates/prefs/StringPreferenceDelegate.kt @@ -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 { + + 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) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt index 70e8decbf..efd1ed497 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt @@ -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 ChipGroup.setChips(data: Iterable, action: ChipsFactory.(T) -> Chip) val chip = factory.action(it) addView(chip) } -} \ No newline at end of file +} + +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) + } + } \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_grid.xml b/app/src/main/res/drawable/ic_grid.xml new file mode 100644 index 000000000..f7c6ef71b --- /dev/null +++ b/app/src/main/res/drawable/ic_grid.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_list.xml b/app/src/main/res/drawable/ic_list.xml new file mode 100644 index 000000000..5570f20b6 --- /dev/null +++ b/app/src/main/res/drawable/ic_list.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_list_detailed.xml b/app/src/main/res/drawable/ic_list_detailed.xml new file mode 100644 index 000000000..a722d1e3b --- /dev/null +++ b/app/src/main/res/drawable/ic_list_detailed.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_list_mode.xml b/app/src/main/res/layout/dialog_list_mode.xml new file mode 100644 index 000000000..3266beffa --- /dev/null +++ b/app/src/main/res/layout/dialog_list_mode.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_manga_list.xml b/app/src/main/res/layout/item_manga_list.xml index 2f63b793b..d664d3d32 100644 --- a/app/src/main/res/layout/item_manga_list.xml +++ b/app/src/main/res/layout/item_manga_list.xml @@ -8,6 +8,7 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/opt_list.xml b/app/src/main/res/menu/opt_list.xml new file mode 100644 index 000000000..02265d9bd --- /dev/null +++ b/app/src/main/res/menu/opt_list.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 000000000..4c8767415 --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/constants.xml b/app/src/main/res/values/constants.xml new file mode 100644 index 000000000..ed7161f72 --- /dev/null +++ b/app/src/main/res/values/constants.xml @@ -0,0 +1,4 @@ + + + list_mode + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 9c088013c..9184a28f1 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,5 +2,6 @@ 5dp 84dp + 120dp 46dp \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index af4c3e7eb..f0443ba7c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,4 +9,8 @@ Network connection error Details Chapters + List + Detailed list + Grid + List mode \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 4d8f55a2b..1d8159803 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,10 +1,11 @@ - - \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..b43e77b5f --- /dev/null +++ b/app/src/main/res/values/themes.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file