From 5ed4d0b6b75f429cee287369717cf1630673e787 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 28 Nov 2020 11:05:27 +0200 Subject: [PATCH] Fully migrate to AdapterDelegates and cleanup code --- .travis.yml | 12 +- app/build.gradle | 2 +- .../java/org/koitharu/kotatsu/KotatsuApp.kt | 4 +- .../base/ui/dialog/CheckBoxAlertDialog.kt | 3 +- .../base/ui/dialog/StorageSelectDialog.kt | 3 +- .../kotatsu/base/ui/dialog/TextInputDialog.kt | 3 +- .../kotatsu/base/ui/list/AdapterUpdater.kt | 1 + .../base/ui/list/BaseRecyclerAdapter.kt | 110 ------------------ .../kotatsu/base/ui/list/BaseViewHolder.kt | 18 --- .../ui/list/OnRecyclerItemClickListener.kt | 10 -- .../base/ui/list/ProgressBarAdapter.kt | 24 ---- .../kotatsu/details/ui/DetailsFragment.kt | 9 +- .../kotatsu/details/ui/DetailsViewModel.kt | 4 +- .../ui/adapter/ChaptersSelectionDecoration.kt | 2 +- .../kotatsu/favourites/FavouritesModule.kt | 5 + .../kotatsu/favourites/data/FavouritesDao.kt | 3 + .../favourites/domain/FavouritesRepository.kt | 4 + .../ui/categories/CategoriesEditDelegate.kt | 4 +- .../favourites/ui/categories/CategoryAD.kt | 2 +- .../FavouritesCategoriesViewModel.kt | 37 +----- .../select/CategoriesSelectAdapter.kt | 45 ------- .../select/CategoryCheckableHolder.kt | 16 --- .../select/FavouriteCategoriesDialog.kt | 81 ++++++------- .../select/MangaCategoriesViewModel.kt | 45 +++++++ .../select/OnCategoryCheckListener.kt | 10 -- .../select/adapter/MangaCaegoryAD.kt | 23 ++++ .../select/adapter/MangaCategoriesAdapter.kt | 37 ++++++ .../select/model/MangaCategoryItem.kt | 7 ++ .../kotatsu/history/ui/HistoryListFragment.kt | 4 +- .../org/koitharu/kotatsu/local/LocalModule.kt | 3 +- .../kotatsu/local/ui/LocalListFragment.kt | 4 +- .../kotatsu/reader/ui/ReaderActivity.kt | 4 +- .../ui/thumbnails/PagesThumbnailsAdapter.kt | 34 ------ .../ui/thumbnails/PagesThumbnailsSheet.kt | 18 +-- .../ui/thumbnails/adapter/PageThumbnailAD.kt | 59 ++++++++++ .../adapter/PageThumbnailAdapter.kt | 20 ++++ .../kotatsu/settings/AppUpdateChecker.kt | 4 +- .../settings/sources/SourcesAdapter.kt | 16 ++- .../sources/SourcesSettingsFragment.kt | 13 ++- .../kotatsu/tracker/ui/FeedViewModel.kt | 5 +- .../kotatsu/widget/AppWidgetModule.kt | 10 ++ .../widget/shelf/CategorySelectAdapter.kt | 35 ------ .../widget/shelf/CategorySelectHolder.kt | 16 --- .../widget/shelf/ShelfConfigActivity.kt | 31 +++-- .../widget/shelf/ShelfConfigViewModel.kt | 32 +++++ .../shelf/adapter/CategorySelectAdapter.kt | 33 ++++++ .../shelf/adapter/CategorySelectItemAD.kt | 23 ++++ .../widget/shelf/model/CategoryItem.kt | 7 ++ 48 files changed, 416 insertions(+), 479 deletions(-) delete mode 100644 app/src/main/java/org/koitharu/kotatsu/base/ui/list/BaseRecyclerAdapter.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/base/ui/list/OnRecyclerItemClickListener.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/base/ui/list/ProgressBarAdapter.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/CategoriesSelectAdapter.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/CategoryCheckableHolder.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/OnCategoryCheckListener.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/adapter/MangaCaegoryAD.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/adapter/MangaCategoriesAdapter.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/model/MangaCategoryItem.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsAdapter.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAD.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAdapter.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/widget/AppWidgetModule.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/widget/shelf/CategorySelectAdapter.kt delete mode 100644 app/src/main/java/org/koitharu/kotatsu/widget/shelf/CategorySelectHolder.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/widget/shelf/adapter/CategorySelectAdapter.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/widget/shelf/adapter/CategorySelectItemAD.kt create mode 100644 app/src/main/java/org/koitharu/kotatsu/widget/shelf/model/CategoryItem.kt diff --git a/.travis.yml b/.travis.yml index 134c73e58..714819fb7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,9 @@ language: android dist: trusty -jdk: - - oraclejdk8 android: components: - - tools - - platform-tools-30.0.3 - - build-tools-30.0.2 - android-30 - licenses: - - android-sdk-preview-license-.+ - - android-sdk-license-.+ - - google-gdk-license-.+ + - build-tools-30.0.2 + - platform-tools-30.0.3 + - tools script: ./gradlew -Dorg.gradle.jvmargs=-Xmx1536m assembleDebug lintDebug \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 3ab5e1a39..1daeefc60 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -95,7 +95,7 @@ dependencies { implementation 'org.koin:koin-android:2.2.0' implementation 'org.koin:koin-android-viewmodel:2.2.0' - implementation 'io.coil-kt:coil-base:1.0.0' + implementation 'io.coil-kt:coil-base:1.1.0' implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0' implementation 'com.tomclaw.cache:cache:1.0' diff --git a/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt b/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt index 7e6f6c5ee..63a8692b7 100644 --- a/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt +++ b/app/src/main/java/org/koitharu/kotatsu/KotatsuApp.kt @@ -29,6 +29,7 @@ import org.koitharu.kotatsu.search.searchModule import org.koitharu.kotatsu.settings.settingsModule import org.koitharu.kotatsu.tracker.trackerModule import org.koitharu.kotatsu.widget.WidgetUpdater +import org.koitharu.kotatsu.widget.appWidgetModule class KotatsuApp : Application() { @@ -77,7 +78,8 @@ class KotatsuApp : Application() { detailsModule, trackerModule, settingsModule, - readerModule + readerModule, + appWidgetModule ) } } diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/CheckBoxAlertDialog.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/CheckBoxAlertDialog.kt index e07b709ff..ec9ad0567 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/CheckBoxAlertDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/CheckBoxAlertDialog.kt @@ -8,7 +8,6 @@ import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog import com.google.android.material.checkbox.MaterialCheckBox -import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.koitharu.kotatsu.R class CheckBoxAlertDialog private constructor(private val delegate: AlertDialog) : @@ -23,7 +22,7 @@ class CheckBoxAlertDialog private constructor(private val delegate: AlertDialog) .inflate(R.layout.dialog_checkbox, null, false) private val checkBox = view.findViewById(android.R.id.checkbox) - private val delegate = MaterialAlertDialogBuilder(context) + private val delegate = AlertDialog.Builder(context) .setView(view) fun setTitle(@StringRes titleResId: Int): Builder { diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/StorageSelectDialog.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/StorageSelectDialog.kt index 594837a7c..ae66acca8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/StorageSelectDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/StorageSelectDialog.kt @@ -7,7 +7,6 @@ import android.view.ViewGroup import android.widget.BaseAdapter import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog -import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.android.synthetic.main.item_storage.view.* import org.koitharu.kotatsu.R import org.koitharu.kotatsu.local.domain.LocalMangaRepository @@ -24,7 +23,7 @@ class StorageSelectDialog private constructor(private val delegate: AlertDialog) class Builder(context: Context, defaultValue: File?, listener: OnStorageSelectListener) { private val adapter = VolumesAdapter(context) - private val delegate = MaterialAlertDialogBuilder(context) + private val delegate = AlertDialog.Builder(context) init { if (adapter.isEmpty) { diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/TextInputDialog.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/TextInputDialog.kt index 8d7634b00..159c52786 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/TextInputDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/dialog/TextInputDialog.kt @@ -7,7 +7,6 @@ import android.text.InputFilter import android.view.LayoutInflater import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog -import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.android.synthetic.main.dialog_input.view.* import org.koitharu.kotatsu.R @@ -23,7 +22,7 @@ class TextInputDialog private constructor( private val view = LayoutInflater.from(context) .inflate(R.layout.dialog_input, null, false) - private val delegate = MaterialAlertDialogBuilder(context) + private val delegate = AlertDialog.Builder(context) .setView(view) fun setTitle(@StringRes titleResId: Int): Builder { diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/AdapterUpdater.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/AdapterUpdater.kt index a68cf666f..9e238487a 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/AdapterUpdater.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/AdapterUpdater.kt @@ -4,6 +4,7 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import java.util.* +@Deprecated("") class AdapterUpdater(oldList: List, newList: List, getId: (T) -> Long) { private val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() { diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/BaseRecyclerAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/BaseRecyclerAdapter.kt deleted file mode 100644 index 679cf2df2..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/BaseRecyclerAdapter.kt +++ /dev/null @@ -1,110 +0,0 @@ -package org.koitharu.kotatsu.base.ui.list - -import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView -import org.koin.core.component.KoinComponent -import org.koitharu.kotatsu.utils.ext.replaceWith - -@Deprecated("", replaceWith = ReplaceWith("AsyncListDifferDelegationAdapter")) -abstract class BaseRecyclerAdapter(private val onItemClickListener: OnRecyclerItemClickListener? = null) : - RecyclerView.Adapter>(), - KoinComponent { - - protected val dataSet = ArrayList() //TODO make private - - val items get() = dataSet as List - - val hasItems get() = dataSet.isNotEmpty() - - init { - @Suppress("LeakingThis") - setHasStableIds(true) - } - - override fun onBindViewHolder(holder: BaseViewHolder, position: Int) { - val item = dataSet[position] - holder.bind(item, getExtra(item, position)) - } - - fun getItem(position: Int) = dataSet[position] - - override fun getItemId(position: Int) = onGetItemId(dataSet[position]) - - protected fun findItemById(id: Long) = dataSet.find { x -> onGetItemId(x) == id } - - protected fun findItemPositionById(id: Long) = - dataSet.indexOfFirst { x -> onGetItemId(x) == id } - - fun replaceData(newData: List) { - val updater = AdapterUpdater(dataSet, newData, this::onGetItemId) - dataSet.replaceWith(newData) - updater(this) - onDataSetChanged() - } - - fun appendData(newData: List) { - val pos = dataSet.size - dataSet.addAll(newData) - notifyItemRangeInserted(pos, newData.size) - onDataSetChanged() - } - - fun prependData(newData: List) { - dataSet.addAll(0, newData) - notifyItemRangeInserted(0, newData.size) - onDataSetChanged() - } - - fun appendItem(newItem: T) { - dataSet.add(newItem) - notifyItemInserted(dataSet.lastIndex) - onDataSetChanged() - } - - fun removeItem(item: T) { - removeItemAt(dataSet.indexOf(item)) - onDataSetChanged() - } - - fun removeItemAt(position: Int) { - if (position in dataSet.indices) { - dataSet.removeAt(position) - notifyItemRemoved(position) - } - onDataSetChanged() - } - - fun clearData() { - dataSet.clear() - notifyDataSetChanged() - onDataSetChanged() - } - - override fun onViewRecycled(holder: BaseViewHolder) { - holder.onRecycled() - } - - final override fun getItemCount() = dataSet.size - - final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder { - return onCreateViewHolder(parent) - } - - override fun onViewDetachedFromWindow(holder: BaseViewHolder) { - holder.setOnItemClickListener(null) - super.onViewDetachedFromWindow(holder) - } - - override fun onViewAttachedToWindow(holder: BaseViewHolder) { - super.onViewAttachedToWindow(holder) - holder.setOnItemClickListener(onItemClickListener) - } - - protected open fun onDataSetChanged() = Unit - - protected abstract fun getExtra(item: T, position: Int): E - - protected abstract fun onCreateViewHolder(parent: ViewGroup): BaseViewHolder - - protected abstract fun onGetItemId(item: T): Long -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/BaseViewHolder.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/BaseViewHolder.kt index 23973901d..0d4b629a5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/BaseViewHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/BaseViewHolder.kt @@ -30,25 +30,7 @@ abstract class BaseViewHolder protected constructor(view: View) : return boundData ?: throw IllegalStateException("Calling requireData() before bind()") } - fun setOnItemClickListener(listener: OnRecyclerItemClickListener?) { - val listenersAdapter = listener?.let { HolderListenersAdapter(it) } - itemView.setOnClickListener(listenersAdapter) - itemView.setOnLongClickListener(listenersAdapter) - } - open fun onRecycled() = Unit abstract fun onBind(data: T, extra: E) - - private inner class HolderListenersAdapter(private val listener: OnRecyclerItemClickListener) : - View.OnClickListener, View.OnLongClickListener { - - override fun onClick(v: View) { - listener.onItemClick(boundData ?: return, bindingAdapterPosition, v) - } - - override fun onLongClick(v: View): Boolean { - return listener.onItemLongClick(boundData ?: return false, bindingAdapterPosition, v) - } - } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/OnRecyclerItemClickListener.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/OnRecyclerItemClickListener.kt deleted file mode 100644 index 47a9465c3..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/OnRecyclerItemClickListener.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.koitharu.kotatsu.base.ui.list - -import android.view.View - -interface OnRecyclerItemClickListener { - - fun onItemClick(item: I, position: Int, view: View) - - fun onItemLongClick(item: I, position: Int, view: View) = false -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/ProgressBarAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/list/ProgressBarAdapter.kt deleted file mode 100644 index 40946886b..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/list/ProgressBarAdapter.kt +++ /dev/null @@ -1,24 +0,0 @@ -package org.koitharu.kotatsu.base.ui.list - -import android.view.ViewGroup - -class ProgressBarAdapter : BaseRecyclerAdapter() { - - var isProgressVisible: Boolean - get() = dataSet.isNotEmpty() - set(value) { - if (value == dataSet.isEmpty()) { - if (value) { - appendItem(true) - } else { - removeItemAt(0) - } - } - } - - override fun getExtra(item: Boolean, position: Int) = Unit - - override fun onCreateViewHolder(parent: ViewGroup) = ProgressBarHolder(parent) - - override fun onGetItemId(item: Boolean) = -1L -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index c73bc1cf4..d6b934876 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -14,7 +14,6 @@ import kotlinx.coroutines.withContext import org.koin.android.viewmodel.ext.android.sharedViewModel import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseFragment -import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesDialog @@ -105,12 +104,12 @@ class DetailsFragment : BaseFragment(R.layout.fragment_details), View.OnClickLis } } - private fun onFavouriteChanged(categories: List) { + private fun onFavouriteChanged(isFavourite: Boolean) { imageView_favourite.setImageResource( - if (categories.isEmpty()) { - R.drawable.ic_heart_outline - } else { + if (isFavourite) { R.drawable.ic_heart + } else { + R.drawable.ic_heart_outline } ) } diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt index 267f7e688..23642ba34 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsViewModel.kt @@ -39,8 +39,8 @@ class DetailsViewModel( private val favourite = mangaData.mapNotNull { it?.id } .distinctUntilChanged() .flatMapLatest { mangaId -> - favouritesRepository.observeCategories(mangaId) - }.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) + favouritesRepository.observeCategoriesIds(mangaId).map { it.isNotEmpty() } + }.stateIn(viewModelScope, SharingStarted.Eagerly, false) private val newChapters = mangaData.mapNotNull { it?.id } .distinctUntilChanged() diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/adapter/ChaptersSelectionDecoration.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/adapter/ChaptersSelectionDecoration.kt index 943ee5391..69ad32f06 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/adapter/ChaptersSelectionDecoration.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/adapter/ChaptersSelectionDecoration.kt @@ -21,7 +21,7 @@ class ChaptersSelectionDecoration(context: Context) : RecyclerView.ItemDecoratio private val paint = Paint(Paint.ANTI_ALIAS_FLAG) init { - paint.color = context.getThemeColor(com.google.android.material.R.attr.colorSurface) + paint.color = context.getThemeColor(com.google.android.material.R.attr.scrimBackground) paint.style = Paint.Style.FILL } diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt index c213051f7..926202ea6 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/FavouritesModule.kt @@ -2,8 +2,10 @@ package org.koitharu.kotatsu.favourites import org.koin.android.viewmodel.dsl.viewModel import org.koin.dsl.module +import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.favourites.domain.FavouritesRepository import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel +import org.koitharu.kotatsu.favourites.ui.categories.select.MangaCategoriesViewModel import org.koitharu.kotatsu.favourites.ui.list.FavouritesListViewModel val favouritesModule @@ -15,4 +17,7 @@ val favouritesModule FavouritesListViewModel(categoryId, get(), get()) } viewModel { FavouritesCategoriesViewModel(get()) } + viewModel { (manga: Manga) -> + MangaCategoriesViewModel(manga, get()) + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/data/FavouritesDao.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/data/FavouritesDao.kt index fba33ef6b..591dda4c9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/data/FavouritesDao.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/data/FavouritesDao.kt @@ -42,6 +42,9 @@ abstract class FavouritesDao { @Query("SELECT * FROM favourites WHERE manga_id = :id GROUP BY manga_id") abstract fun observe(id: Long): Flow + @Query("SELECT DISTINCT category_id FROM favourites WHERE manga_id = :id") + abstract fun observeIds(id: Long): Flow> + @Insert(onConflict = OnConflictStrategy.IGNORE) abstract suspend fun insert(favourite: FavouriteEntity) diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt index 6008c793c..ddd14e256 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/domain/FavouritesRepository.kt @@ -70,6 +70,10 @@ class FavouritesRepository(private val db: MangaDatabase) { } } + fun observeCategoriesIds(mangaId: Long): Flow> { + return db.favouritesDao.observeIds(mangaId) + } + suspend fun addCategory(title: String): FavouriteCategory { val entity = FavouriteCategoryEntity( title = title, diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt index b60762f11..e10ec58ee 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoriesEditDelegate.kt @@ -2,7 +2,7 @@ package org.koitharu.kotatsu.favourites.ui.categories import android.content.Context import android.text.InputType -import com.google.android.material.dialog.MaterialAlertDialogBuilder +import androidx.appcompat.app.AlertDialog import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.dialog.TextInputDialog import org.koitharu.kotatsu.core.model.FavouriteCategory @@ -13,7 +13,7 @@ class CategoriesEditDelegate( ) { fun deleteCategory(category: FavouriteCategory) { - MaterialAlertDialogBuilder(context) + AlertDialog.Builder(context) .setMessage(context.getString(R.string.category_delete_confirm, category.title)) .setTitle(R.string.remove_category) .setNegativeButton(android.R.string.cancel, null) diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoryAD.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoryAD.kt index 8e4884508..0bfd98070 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoryAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/CategoryAD.kt @@ -17,7 +17,7 @@ fun categoryAD( @Suppress("ClickableViewAccessibility") imageView_handle.setOnTouchListener { v, event -> if (event.actionMasked == MotionEvent.ACTION_DOWN) { - clickListener.onItemLongClick(item, v) + clickListener.onItemLongClick(item, itemView) } else { false } diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt index c13747aeb..557515cba 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/FavouritesCategoriesViewModel.kt @@ -1,59 +1,42 @@ package org.koitharu.kotatsu.favourites.ui.categories -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.plus import org.koitharu.kotatsu.base.ui.BaseViewModel -import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.favourites.domain.FavouritesRepository -import org.koitharu.kotatsu.utils.ext.mapToSet class FavouritesCategoriesViewModel( private val repository: FavouritesRepository ) : BaseViewModel() { private var reorderJob: Job? = null - private var mangaSubscription: Job? = null val categories = repository.observeCategories() .asLiveData(viewModelScope.coroutineContext + Dispatchers.Default) - val mangaCategories = MutableLiveData>(emptySet()) - - fun observeMangaCategories(mangaId: Long) { - mangaSubscription?.cancel() - mangaSubscription = repository.observeCategories(mangaId) - .map { list -> list.mapToSet { it.id } } - .onEach { mangaCategories.postValue(it) } - .launchIn(viewModelScope + Dispatchers.Default) - } fun createCategory(name: String) { - launchJob { + launchJob(Dispatchers.Default) { repository.addCategory(name) } } fun renameCategory(id: Long, name: String) { - launchJob { + launchJob(Dispatchers.Default) { repository.renameCategory(id, name) } } fun deleteCategory(id: Long) { - launchJob { + launchJob(Dispatchers.Default) { repository.removeCategory(id) } } fun reorderCategories(oldPos: Int, newPos: Int) { val prevJob = reorderJob - reorderJob = launchJob { + reorderJob = launchJob(Dispatchers.Default) { prevJob?.join() val items = categories.value ?: error("This should not happen") val ids = items.mapTo(ArrayList(items.size)) { it.id } @@ -62,16 +45,4 @@ class FavouritesCategoriesViewModel( repository.reorderCategories(ids) } } - - fun addToCategory(manga: Manga, categoryId: Long) { - launchJob { - repository.addToCategory(manga, categoryId) - } - } - - fun removeFromCategory(manga: Manga, categoryId: Long) { - launchJob { - repository.removeFromCategory(manga, categoryId) - } - } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/CategoriesSelectAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/CategoriesSelectAdapter.kt deleted file mode 100644 index bb93fa74f..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/CategoriesSelectAdapter.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.koitharu.kotatsu.favourites.ui.categories.select - -import android.view.ViewGroup -import android.widget.Checkable -import androidx.collection.ArraySet -import org.koitharu.kotatsu.base.ui.list.BaseRecyclerAdapter -import org.koitharu.kotatsu.base.ui.list.BaseViewHolder -import org.koitharu.kotatsu.core.model.FavouriteCategory - -class CategoriesSelectAdapter(private val listener: OnCategoryCheckListener) : - BaseRecyclerAdapter() { - - private val checkedIds = ArraySet() - - fun setCheckedIds(ids: Iterable) { - checkedIds.clear() - checkedIds.addAll(ids) - notifyDataSetChanged() - } - - override fun getExtra(item: FavouriteCategory, position: Int) = item.id in checkedIds - - override fun onCreateViewHolder(parent: ViewGroup) = - CategoryCheckableHolder( - parent - ) - - override fun onGetItemId(item: FavouriteCategory) = item.id - - override fun onViewDetachedFromWindow(holder: BaseViewHolder) { - holder.itemView.setOnClickListener(null) - } - - override fun onViewAttachedToWindow(holder: BaseViewHolder) { - holder.itemView.setOnClickListener { - if (it !is Checkable) return@setOnClickListener - it.toggle() - if (it.isChecked) { - listener.onCategoryChecked(holder.requireData()) - } else { - listener.onCategoryUnchecked(holder.requireData()) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/CategoryCheckableHolder.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/CategoryCheckableHolder.kt deleted file mode 100644 index f9f534c84..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/CategoryCheckableHolder.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.koitharu.kotatsu.favourites.ui.categories.select - -import android.view.ViewGroup -import kotlinx.android.synthetic.main.item_category_checkable.* -import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.base.ui.list.BaseViewHolder -import org.koitharu.kotatsu.core.model.FavouriteCategory - -class CategoryCheckableHolder(parent: ViewGroup) : - BaseViewHolder(parent, R.layout.item_category_checkable) { - - override fun onBind(data: FavouriteCategory, extra: Boolean) { - checkedTextView.text = data.title - checkedTextView.isChecked = extra - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesDialog.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesDialog.kt index 26de7258a..2754a9264 100644 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/FavouriteCategoriesDialog.kt @@ -1,46 +1,44 @@ package org.koitharu.kotatsu.favourites.ui.categories.select import android.os.Bundle -import android.text.InputType import android.view.View import android.widget.Toast import androidx.fragment.app.FragmentManager import kotlinx.android.synthetic.main.dialog_favorite_categories.* import org.koin.android.viewmodel.ext.android.viewModel +import org.koin.core.parameter.parametersOf import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.domain.MangaIntent import org.koitharu.kotatsu.base.ui.BaseBottomSheet -import org.koitharu.kotatsu.base.ui.dialog.TextInputDialog +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.model.FavouriteCategory import org.koitharu.kotatsu.core.model.Manga -import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel +import org.koitharu.kotatsu.favourites.ui.categories.CategoriesEditDelegate +import org.koitharu.kotatsu.favourites.ui.categories.select.adapter.MangaCategoriesAdapter +import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.withArgs class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categories), - OnCategoryCheckListener { + OnListItemClickListener, CategoriesEditDelegate.CategoriesEditCallback, + View.OnClickListener { - private val viewModel by viewModel() + private val viewModel by viewModel { + parametersOf(requireNotNull(arguments?.getParcelable(MangaIntent.KEY_MANGA))) + } - private val manga get() = arguments?.getParcelable(ARG_MANGA) - - private var adapter: CategoriesSelectAdapter? = null + private var adapter: MangaCategoriesAdapter? = null + private val editDelegate by lazy(LazyThreadSafetyMode.NONE) { + CategoriesEditDelegate(requireContext(), this@FavouriteCategoriesDialog) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - adapter = - CategoriesSelectAdapter( - this - ) + adapter = MangaCategoriesAdapter(this) recyclerView_categories.adapter = adapter - textView_add.setOnClickListener { - createCategory() - } - manga?.let { - viewModel.observeMangaCategories(it.id) - } + textView_add.setOnClickListener(this) - viewModel.categories.observe(viewLifecycleOwner, ::onCategoriesChanged) - viewModel.mangaCategories.observe(viewLifecycleOwner, ::onCheckedCategoriesChanged) + viewModel.content.observe(viewLifecycleOwner, this::onContentChanged) viewModel.onError.observe(viewLifecycleOwner, ::onError) } @@ -49,50 +47,39 @@ class FavouriteCategoriesDialog : BaseBottomSheet(R.layout.dialog_favorite_categ super.onDestroyView() } - private fun onCategoriesChanged(categories: List) { - adapter?.replaceData(categories) + override fun onClick(v: View) { + when (v.id) { + R.id.textView_add -> editDelegate.createCategory() + } } - private fun onCheckedCategoriesChanged(checkedIds: Set) { - adapter?.setCheckedIds(checkedIds) + override fun onItemClick(item: MangaCategoryItem, view: View) { + viewModel.setChecked(item.id, !item.isChecked) } - override fun onCategoryChecked(category: FavouriteCategory) { - viewModel.addToCategory(manga ?: return, category.id) + override fun onDeleteCategory(category: FavouriteCategory) = Unit + + override fun onRenameCategory(category: FavouriteCategory, newName: String) = Unit + + override fun onCreateCategory(name: String) { + viewModel.createCategory(name) } - override fun onCategoryUnchecked(category: FavouriteCategory) { - viewModel.removeFromCategory(manga ?: return, category.id) + private fun onContentChanged(categories: List) { + adapter?.items = categories } private fun onError(e: Throwable) { Toast.makeText(context ?: return, e.getDisplayMessage(resources), Toast.LENGTH_SHORT).show() } - private fun createCategory() { - TextInputDialog.Builder(context ?: return) - .setTitle(R.string.add_new_category) - .setHint(R.string.enter_category_name) - .setMaxLength(12, false) - .setInputType(InputType.TYPE_TEXT_VARIATION_PERSON_NAME or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) - .setNegativeButton(android.R.string.cancel) - .setPositiveButton(R.string.add) { _, name -> - viewModel.createCategory(name) - }.create() - .show() - } - companion object { - private const val ARG_MANGA = "manga" private const val TAG = "FavouriteCategoriesDialog" fun show(fm: FragmentManager, manga: Manga) = FavouriteCategoriesDialog() .withArgs(1) { - putParcelable(ARG_MANGA, manga) - }.show( - fm, - TAG - ) + putParcelable(MangaIntent.KEY_MANGA, manga) + }.show(fm, TAG) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt new file mode 100644 index 000000000..ced611e9c --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/MangaCategoriesViewModel.kt @@ -0,0 +1,45 @@ +package org.koitharu.kotatsu.favourites.ui.categories.select + +import androidx.lifecycle.asLiveData +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.combine +import org.koitharu.kotatsu.base.ui.BaseViewModel +import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.favourites.domain.FavouritesRepository +import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem + +class MangaCategoriesViewModel( + private val manga: Manga, + private val favouritesRepository: FavouritesRepository +) : BaseViewModel() { + + val content = combine( + favouritesRepository.observeCategories(), + favouritesRepository.observeCategoriesIds(manga.id) + ) { all, checked -> + all.map { + MangaCategoryItem( + id = it.id, + name = it.title, + isChecked = it.id in checked + ) + } + }.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default) + + fun setChecked(categoryId: Long, isChecked: Boolean) { + launchJob(Dispatchers.Default) { + if (isChecked) { + favouritesRepository.addToCategory(manga, categoryId) + } else { + favouritesRepository.removeFromCategory(manga, categoryId) + } + } + } + + fun createCategory(name: String) { + launchJob(Dispatchers.Default) { + favouritesRepository.addCategory(name) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/OnCategoryCheckListener.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/OnCategoryCheckListener.kt deleted file mode 100644 index 516524739..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/OnCategoryCheckListener.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.koitharu.kotatsu.favourites.ui.categories.select - -import org.koitharu.kotatsu.core.model.FavouriteCategory - -interface OnCategoryCheckListener { - - fun onCategoryChecked(category: FavouriteCategory) - - fun onCategoryUnchecked(category: FavouriteCategory) -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/adapter/MangaCaegoryAD.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/adapter/MangaCaegoryAD.kt new file mode 100644 index 000000000..ae84a47d6 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/adapter/MangaCaegoryAD.kt @@ -0,0 +1,23 @@ +package org.koitharu.kotatsu.favourites.ui.categories.select.adapter + +import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateLayoutContainer +import kotlinx.android.synthetic.main.item_category_checkable.* +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem + +fun mangaCategoryAD( + clickListener: OnListItemClickListener +) = adapterDelegateLayoutContainer( + R.layout.item_category_checkable +) { + + itemView.setOnClickListener { + clickListener.onItemClick(item, itemView) + } + + bind { + checkedTextView.text = item.name + checkedTextView.isChecked = item.isChecked + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/adapter/MangaCategoriesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/adapter/MangaCategoriesAdapter.kt new file mode 100644 index 000000000..df6e54ca0 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/adapter/MangaCategoriesAdapter.kt @@ -0,0 +1,37 @@ +package org.koitharu.kotatsu.favourites.ui.categories.select.adapter + +import androidx.recyclerview.widget.DiffUtil +import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem + +class MangaCategoriesAdapter( + clickListener: OnListItemClickListener +) : AsyncListDifferDelegationAdapter(DiffCallback()) { + + init { + delegatesManager.addDelegate(mangaCategoryAD(clickListener)) + } + + private class DiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame( + oldItem: MangaCategoryItem, + newItem: MangaCategoryItem + ): Boolean = oldItem.id == newItem.id + + override fun areContentsTheSame( + oldItem: MangaCategoryItem, + newItem: MangaCategoryItem + ): Boolean = oldItem == newItem + + override fun getChangePayload( + oldItem: MangaCategoryItem, + newItem: MangaCategoryItem + ): Any? { + if (oldItem.isChecked != newItem.isChecked) { + return newItem.isChecked + } + return super.getChangePayload(oldItem, newItem) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/model/MangaCategoryItem.kt b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/model/MangaCategoryItem.kt new file mode 100644 index 000000000..95447a2af --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/favourites/ui/categories/select/model/MangaCategoryItem.kt @@ -0,0 +1,7 @@ +package org.koitharu.kotatsu.favourites.ui.categories.select.model + +data class MangaCategoryItem( + val id: Long, + val name: String, + val isChecked: Boolean +) \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListFragment.kt index 7743dc3f2..2dcc7cefb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/history/ui/HistoryListFragment.kt @@ -5,7 +5,7 @@ import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import com.google.android.material.dialog.MaterialAlertDialogBuilder +import androidx.appcompat.app.AlertDialog import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.fragment_list.* import org.koin.android.viewmodel.ext.android.viewModel @@ -34,7 +34,7 @@ class HistoryListFragment : MangaListFragment() { override fun onOptionsItemSelected(item: MenuItem): Boolean { return when (item.itemId) { R.id.action_clear_history -> { - MaterialAlertDialogBuilder(context ?: return false) + AlertDialog.Builder(context ?: return false) .setTitle(R.string.clear_history) .setMessage(R.string.text_clear_history_prompt) .setNegativeButton(android.R.string.cancel, null) diff --git a/app/src/main/java/org/koitharu/kotatsu/local/LocalModule.kt b/app/src/main/java/org/koitharu/kotatsu/local/LocalModule.kt index 7a03d64ca..bfdbc21f5 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/LocalModule.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/LocalModule.kt @@ -5,6 +5,7 @@ import org.koin.android.viewmodel.dsl.viewModel import org.koin.core.qualifier.named import org.koin.dsl.module import org.koitharu.kotatsu.core.model.MangaSource +import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.local.domain.LocalMangaRepository import org.koitharu.kotatsu.local.ui.LocalListViewModel @@ -12,7 +13,7 @@ val localModule get() = module { single { LocalMangaRepository(androidContext()) } - factory(named(MangaSource.LOCAL)) { get() } + factory(named(MangaSource.LOCAL)) { get() } viewModel { LocalListViewModel(get(), get(), get(), androidContext()) } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListFragment.kt index 8266299ab..36da2d8aa 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/ui/LocalListFragment.kt @@ -9,7 +9,7 @@ import android.view.MenuItem import android.view.View import androidx.activity.result.ActivityResultCallback import androidx.activity.result.contract.ActivityResultContracts -import com.google.android.material.dialog.MaterialAlertDialogBuilder +import androidx.appcompat.app.AlertDialog import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.fragment_list.* import org.koin.android.viewmodel.ext.android.viewModel @@ -86,7 +86,7 @@ class LocalListFragment : MangaListFragment(), ActivityResultCallback { override fun onPopupMenuItemSelected(item: MenuItem, data: Manga): Boolean { return when (item.itemId) { R.id.action_delete -> { - MaterialAlertDialogBuilder(context ?: return false) + AlertDialog.Builder(context ?: return false) .setTitle(R.string.delete_manga) .setMessage(getString(R.string.text_delete_local_manga, data.title)) .setPositiveButton(R.string.delete) { _, _ -> diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt index c313e88aa..7bde0b214 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderActivity.kt @@ -12,12 +12,12 @@ import android.view.* import android.widget.Toast import androidx.activity.result.ActivityResultCallback import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.core.graphics.Insets import androidx.core.view.* import androidx.fragment.app.commit import androidx.lifecycle.lifecycleScope -import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.activity_reader.* import kotlinx.coroutines.Dispatchers @@ -247,7 +247,7 @@ class ReaderActivity : BaseFullscreenActivity(), ChaptersDialog.OnChapterChangeL } override fun onError(e: Throwable) { - val dialog = MaterialAlertDialogBuilder(this) + val dialog = AlertDialog.Builder(this) .setTitle(R.string.error_occurred) .setMessage(e.message) .setPositiveButton(R.string.close, null) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsAdapter.kt deleted file mode 100644 index 1d5f78c51..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsAdapter.kt +++ /dev/null @@ -1,34 +0,0 @@ -package org.koitharu.kotatsu.reader.ui.thumbnails - -import android.view.ViewGroup -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.DisposableHandle -import kotlinx.coroutines.SupervisorJob -import org.koin.core.component.inject -import org.koitharu.kotatsu.base.ui.list.BaseRecyclerAdapter -import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener -import org.koitharu.kotatsu.core.model.MangaPage -import org.koitharu.kotatsu.local.data.PagesCache -import kotlin.coroutines.CoroutineContext - -class PagesThumbnailsAdapter(onItemClickListener: OnRecyclerItemClickListener?) : - BaseRecyclerAdapter(onItemClickListener), CoroutineScope, - DisposableHandle { - - private val job = SupervisorJob() - private val cache by inject() - - override val coroutineContext: CoroutineContext - get() = Dispatchers.Main.immediate + job - - override fun dispose() { - job.cancel() - } - - override fun getExtra(item: MangaPage, position: Int) = cache - - override fun onCreateViewHolder(parent: ViewGroup) = PageThumbnailHolder(parent, this) - - override fun onGetItemId(item: MangaPage) = item.id -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt index 49e4c4ef8..d88fb63f8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/PagesThumbnailsSheet.kt @@ -8,30 +8,32 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import kotlinx.android.synthetic.main.sheet_pages.* import kotlinx.coroutines.DisposableHandle +import org.koin.android.ext.android.get import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseBottomSheet -import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration import org.koitharu.kotatsu.core.model.MangaPage +import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter import org.koitharu.kotatsu.utils.UiUtils import org.koitharu.kotatsu.utils.ext.resolveDp +import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.withArgs class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages), - OnRecyclerItemClickListener { + OnListItemClickListener { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) recyclerView.addItemDecoration(SpacingItemDecoration(view.resources.resolveDp(8))) val pages = arguments?.getParcelableArrayList(ARG_PAGES) - if (pages != null) { - recyclerView.adapter = PagesThumbnailsAdapter(this).apply { - replaceData(pages) - } - } else { + if (pages == null) { dismissAllowingStateLoss() return } + recyclerView.adapter = PageThumbnailAdapter(get(), viewLifecycleScope, get(), this).apply { + items = pages + } val title = arguments?.getString(ARG_TITLE) toolbar.title = title toolbar.setNavigationOnClickListener { dismiss() } @@ -74,7 +76,7 @@ class PagesThumbnailsSheet : BaseBottomSheet(R.layout.sheet_pages), super.onDestroyView() } - override fun onItemClick(item: MangaPage, position: Int, view: View) { + override fun onItemClick(item: MangaPage, view: View) { ((parentFragment as? OnPageSelectListener) ?: (activity as? OnPageSelectListener))?.run { onPageSelected(item) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAD.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAD.kt new file mode 100644 index 000000000..bd89a5b16 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAD.kt @@ -0,0 +1,59 @@ +package org.koitharu.kotatsu.reader.ui.thumbnails.adapter + +import androidx.core.net.toUri +import coil.ImageLoader +import coil.request.ImageRequest +import coil.size.PixelSize +import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateLayoutContainer +import kotlinx.android.synthetic.main.item_page_thumb.* +import kotlinx.coroutines.* +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.model.MangaPage +import org.koitharu.kotatsu.local.data.PagesCache +import org.koitharu.kotatsu.utils.ext.IgnoreErrors + +fun pageThumbnailAD( + coil: ImageLoader, + scope: CoroutineScope, + cache: PagesCache, + clickListener: OnListItemClickListener +) = adapterDelegateLayoutContainer(R.layout.item_page_thumb) { + + var job: Job? = null + val gridWidth = itemView.context.resources.getDimensionPixelSize(R.dimen.preferred_grid_width) + val thumbSize = PixelSize( + width = gridWidth, + height = (gridWidth * 13f / 18f).toInt() + ) + + handle.setOnClickListener { + clickListener.onItemClick(item, itemView) + } + + bind { + job?.cancel() + imageView_thumb.setImageDrawable(null) + textView_number.text = (bindingAdapterPosition + 1).toString() + job = scope.launch(Dispatchers.Default + IgnoreErrors) { + val url = item.preview ?: item.url.let { + val pageUrl = item.source.repository.getPageFullUrl(item) + cache[pageUrl]?.toUri()?.toString() ?: pageUrl + } + val drawable = coil.execute( + ImageRequest.Builder(context) + .data(url) + .size(thumbSize) + .build() + ).drawable + withContext(Dispatchers.Main) { + imageView_thumb.setImageDrawable(drawable) + } + } + } + + onViewRecycled { + job?.cancel() + imageView_thumb.setImageDrawable(null) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAdapter.kt new file mode 100644 index 000000000..4533910f0 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAdapter.kt @@ -0,0 +1,20 @@ +package org.koitharu.kotatsu.reader.ui.thumbnails.adapter + +import coil.ImageLoader +import com.hannesdorfmann.adapterdelegates4.ListDelegationAdapter +import kotlinx.coroutines.CoroutineScope +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.core.model.MangaPage +import org.koitharu.kotatsu.local.data.PagesCache + +class PageThumbnailAdapter( + coil: ImageLoader, + scope: CoroutineScope, + cache: PagesCache, + clickListener: OnListItemClickListener +) : ListDelegationAdapter>() { + + init { + delegatesManager.addDelegate(pageThumbnailAD(coil, scope, cache, clickListener)) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/AppUpdateChecker.kt b/app/src/main/java/org/koitharu/kotatsu/settings/AppUpdateChecker.kt index dbc9f002b..f1e4446fa 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/AppUpdateChecker.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/AppUpdateChecker.kt @@ -6,8 +6,8 @@ import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import androidx.activity.ComponentActivity +import androidx.appcompat.app.AlertDialog import androidx.lifecycle.lifecycleScope -import com.google.android.material.dialog.MaterialAlertDialogBuilder import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -68,7 +68,7 @@ class AppUpdateChecker(private val activity: ComponentActivity) { } private fun showUpdateDialog(version: AppVersion) { - MaterialAlertDialogBuilder(activity) + AlertDialog.Builder(activity) .setTitle(R.string.app_update_available) .setMessage(buildString { append(activity.getString(R.string.new_version_s, version.name)) diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesAdapter.kt index 298b9a0d5..3b12c1798 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesAdapter.kt @@ -5,20 +5,19 @@ import android.view.MotionEvent import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.item_source_config.* -import org.koin.core.component.KoinComponent -import org.koin.core.component.inject import org.koitharu.kotatsu.base.domain.MangaProviderFactory -import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.utils.ext.mapToSet import org.koitharu.kotatsu.utils.ext.safe -class SourcesAdapter(private val onItemClickListener: OnRecyclerItemClickListener) : - RecyclerView.Adapter(), KoinComponent { +class SourcesAdapter( + private val settings: AppSettings, + private val onItemClickListener: OnListItemClickListener, +) : RecyclerView.Adapter() { private val dataSet = MangaProviderFactory.getSources(includeHidden = true).toMutableList() - private val settings by inject() private val hiddenItems = settings.hiddenSources.mapNotNull { safe { MangaSource.valueOf(it) @@ -48,14 +47,13 @@ class SourcesAdapter(private val onItemClickListener: OnRecyclerItemClickListene settings.hiddenSources = hiddenItems.mapToSet { x -> x.name } } holder.imageView_config.setOnClickListener { v -> - onItemClickListener.onItemClick(holder.requireData(), holder.bindingAdapterPosition, v) + onItemClickListener.onItemClick(holder.requireData(), v) } holder.imageView_handle.setOnTouchListener { v, event -> if (event.actionMasked == MotionEvent.ACTION_DOWN) { onItemClickListener.onItemLongClick( holder.requireData(), - holder.bindingAdapterPosition, - v + holder.itemView ) } else { false diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsFragment.kt index 0a3871867..51d1ac860 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/sources/SourcesSettingsFragment.kt @@ -6,14 +6,15 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView import kotlinx.android.synthetic.main.fragment_settings_sources.* +import org.koin.android.ext.android.get import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseFragment -import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.settings.SettingsActivity class SourcesSettingsFragment : BaseFragment(R.layout.fragment_settings_sources), - OnRecyclerItemClickListener { + OnListItemClickListener { private lateinit var reorderHelper: ItemTouchHelper @@ -30,7 +31,7 @@ class SourcesSettingsFragment : BaseFragment(R.layout.fragment_settings_sources) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) recyclerView.addItemDecoration(DividerItemDecoration(view.context, RecyclerView.VERTICAL)) - recyclerView.adapter = SourcesAdapter(this) + recyclerView.adapter = SourcesAdapter(get(), this) reorderHelper.attachToRecyclerView(recyclerView) } @@ -39,13 +40,13 @@ class SourcesSettingsFragment : BaseFragment(R.layout.fragment_settings_sources) super.onDestroyView() } - override fun onItemClick(item: MangaSource, position: Int, view: View) { + override fun onItemClick(item: MangaSource, view: View) { (activity as? SettingsActivity)?.openMangaSourceSettings(item) } - override fun onItemLongClick(item: MangaSource, position: Int, view: View): Boolean { + override fun onItemLongClick(item: MangaSource, view: View): Boolean { reorderHelper.startDrag( - recyclerView.findViewHolderForAdapterPosition(position) ?: return false + recyclerView.findContainingViewHolder(view) ?: return false ) return true } diff --git a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedViewModel.kt index 85f4bbc91..c3da6366b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedViewModel.kt +++ b/app/src/main/java/org/koitharu/kotatsu/tracker/ui/FeedViewModel.kt @@ -43,15 +43,14 @@ class FeedViewModel( if (loadingJob?.isActive == true) { return } - loadingJob = launchLoadingJob { + loadingJob = launchLoadingJob(Dispatchers.Default) { val offset = if (append) logList.value.size else 0 val list = repository.getTrackingLog(offset, 20) if (!append) { logList.value = list + isEmptyState.postValue(list.isEmpty()) } else if (list.isNotEmpty()) { logList.value += list - } else { - isEmptyState.value = true } hasNextPage.value = list.isNotEmpty() } diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/AppWidgetModule.kt b/app/src/main/java/org/koitharu/kotatsu/widget/AppWidgetModule.kt new file mode 100644 index 000000000..41a45f413 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/widget/AppWidgetModule.kt @@ -0,0 +1,10 @@ +package org.koitharu.kotatsu.widget + +import org.koin.android.viewmodel.dsl.viewModel +import org.koin.dsl.module +import org.koitharu.kotatsu.widget.shelf.ShelfConfigViewModel + +val appWidgetModule + get() = module { + viewModel { ShelfConfigViewModel(get()) } + } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/CategorySelectAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/CategorySelectAdapter.kt deleted file mode 100644 index 98937d999..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/CategorySelectAdapter.kt +++ /dev/null @@ -1,35 +0,0 @@ -package org.koitharu.kotatsu.widget.shelf - -import android.view.ViewGroup -import org.koitharu.kotatsu.base.ui.list.BaseRecyclerAdapter -import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener -import org.koitharu.kotatsu.core.model.FavouriteCategory - -class CategorySelectAdapter(onItemClickListener: OnRecyclerItemClickListener? = null) : - BaseRecyclerAdapter(onItemClickListener) { - - var checkedItemId = 0L - private set - - fun setCheckedId(id: Long) { - val oldId = checkedItemId - checkedItemId = id - val oldPos = findItemPositionById(oldId) - val newPos = findItemPositionById(id) - if (newPos != -1) { - notifyItemChanged(newPos) - } - if (oldPos != -1) { - notifyItemChanged(oldPos) - } - } - - override fun getExtra(item: FavouriteCategory, position: Int) = - checkedItemId == item.id - - override fun onCreateViewHolder(parent: ViewGroup) = CategorySelectHolder( - parent - ) - - override fun onGetItemId(item: FavouriteCategory) = item.id -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/CategorySelectHolder.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/CategorySelectHolder.kt deleted file mode 100644 index a36c7b4fc..000000000 --- a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/CategorySelectHolder.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.koitharu.kotatsu.widget.shelf - -import android.view.ViewGroup -import kotlinx.android.synthetic.main.item_category_checkable.* -import org.koitharu.kotatsu.R -import org.koitharu.kotatsu.base.ui.list.BaseViewHolder -import org.koitharu.kotatsu.core.model.FavouriteCategory - -class CategorySelectHolder(parent: ViewGroup) : - BaseViewHolder(parent, R.layout.item_category_checkable_single) { - - override fun onBind(data: FavouriteCategory, extra: Boolean) { - checkedTextView.text = data.title - checkedTextView.isChecked = extra - } -} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt index 97dbd0768..011996af9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigActivity.kt @@ -17,17 +17,15 @@ import kotlinx.android.synthetic.main.activity_categories.* import org.koin.android.viewmodel.ext.android.viewModel import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.BaseActivity -import org.koitharu.kotatsu.base.ui.list.OnRecyclerItemClickListener -import org.koitharu.kotatsu.core.model.FavouriteCategory +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.prefs.AppWidgetConfig -import org.koitharu.kotatsu.favourites.ui.categories.FavouritesCategoriesViewModel import org.koitharu.kotatsu.utils.ext.getDisplayMessage -import java.util.* -import kotlin.collections.ArrayList +import org.koitharu.kotatsu.widget.shelf.adapter.CategorySelectAdapter +import org.koitharu.kotatsu.widget.shelf.model.CategoryItem -class ShelfConfigActivity : BaseActivity(), OnRecyclerItemClickListener { +class ShelfConfigActivity : BaseActivity(), OnListItemClickListener { - private val viewModel by viewModel() + private val viewModel by viewModel() private lateinit var adapter: CategorySelectAdapter private lateinit var config: AppWidgetConfig @@ -50,10 +48,10 @@ class ShelfConfigActivity : BaseActivity(), OnRecyclerItemClickListener { - config.categoryId = adapter.checkedItemId + config.categoryId = viewModel.checkedId updateWidget() setResult( Activity.RESULT_OK, @@ -75,15 +73,12 @@ class ShelfConfigActivity : BaseActivity(), OnRecyclerItemClickListener super.onOptionsItemSelected(item) } - override fun onItemClick(item: FavouriteCategory, position: Int, view: View) { - adapter.setCheckedId(item.id) + override fun onItemClick(item: CategoryItem, view: View) { + viewModel.checkedId = item.id } - private fun onCategoriesChanged(categories: List) { - val data = ArrayList(categories.size + 1) - data += FavouriteCategory(0L, getString(R.string.all_favourites), -1, Date()) - data += categories - adapter.replaceData(data) + private fun onContentChanged(categories: List) { + adapter.items = categories } private fun onError(e: Throwable) { diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt new file mode 100644 index 000000000..c6fc30181 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/ShelfConfigViewModel.kt @@ -0,0 +1,32 @@ +package org.koitharu.kotatsu.widget.shelf + +import androidx.lifecycle.asLiveData +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.combine +import org.koitharu.kotatsu.base.ui.BaseViewModel +import org.koitharu.kotatsu.favourites.domain.FavouritesRepository +import org.koitharu.kotatsu.widget.shelf.model.CategoryItem +import java.util.* + +class ShelfConfigViewModel( + favouritesRepository: FavouritesRepository +) : BaseViewModel() { + + private val selectedCategoryId = MutableStateFlow(0L) + + val content = combine( + favouritesRepository.observeCategories(), + selectedCategoryId + ) { categories, selectedId -> + val list = ArrayList(categories.size + 1) + list += CategoryItem(0L, null, selectedId == 0L) + categories.mapTo(list) { + CategoryItem(it.id, it.title, selectedId == it.id) + } + list + }.asLiveData(viewModelScope.coroutineContext + Dispatchers.Default) + + var checkedId: Long by selectedCategoryId::value +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/adapter/CategorySelectAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/adapter/CategorySelectAdapter.kt new file mode 100644 index 000000000..39f90c22e --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/adapter/CategorySelectAdapter.kt @@ -0,0 +1,33 @@ +package org.koitharu.kotatsu.widget.shelf.adapter + +import androidx.recyclerview.widget.DiffUtil +import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.widget.shelf.model.CategoryItem + +class CategorySelectAdapter( + clickListener: OnListItemClickListener +) : AsyncListDifferDelegationAdapter(DiffCallback()) { + + init { + delegatesManager.addDelegate(categorySelectItemAD(clickListener)) + } + + private class DiffCallback : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: CategoryItem, newItem: CategoryItem): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: CategoryItem, newItem: CategoryItem): Boolean { + return oldItem == newItem + } + + override fun getChangePayload(oldItem: CategoryItem, newItem: CategoryItem): Any? { + if (oldItem.isSelected != newItem.isSelected) { + return newItem.isSelected + } + return super.getChangePayload(oldItem, newItem) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/adapter/CategorySelectItemAD.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/adapter/CategorySelectItemAD.kt new file mode 100644 index 000000000..b71cff6f3 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/adapter/CategorySelectItemAD.kt @@ -0,0 +1,23 @@ +package org.koitharu.kotatsu.widget.shelf.adapter + +import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateLayoutContainer +import kotlinx.android.synthetic.main.item_category_checkable.* +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener +import org.koitharu.kotatsu.widget.shelf.model.CategoryItem + +fun categorySelectItemAD( + clickListener: OnListItemClickListener +) = adapterDelegateLayoutContainer( + R.layout.item_category_checkable_single +) { + + itemView.setOnClickListener { + clickListener.onItemClick(item, it) + } + + bind { + checkedTextView.text = item.name ?: getString(R.string.all_favourites) + checkedTextView.isChecked = item.isSelected + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/widget/shelf/model/CategoryItem.kt b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/model/CategoryItem.kt new file mode 100644 index 000000000..0407dd18a --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/widget/shelf/model/CategoryItem.kt @@ -0,0 +1,7 @@ +package org.koitharu.kotatsu.widget.shelf.model + +data class CategoryItem( + val id: Long, + val name: String?, + val isSelected: Boolean +) \ No newline at end of file