mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Migrate to more use of domain models
This commit is contained in:
		| @@ -2,6 +2,9 @@ package eu.kanade.domain.category.model | ||||
|  | ||||
| import android.content.Context | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting | ||||
| import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting | ||||
| import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting | ||||
| import java.io.Serializable | ||||
| import eu.kanade.tachiyomi.data.database.models.Category as DbCategory | ||||
|  | ||||
| @@ -12,6 +15,15 @@ data class Category( | ||||
|     val flags: Long, | ||||
| ) : Serializable { | ||||
|  | ||||
|     val displayMode: Long | ||||
|         get() = flags and DisplayModeSetting.MASK | ||||
|  | ||||
|     val sortMode: Long | ||||
|         get() = flags and SortModeSetting.MASK | ||||
|  | ||||
|     val sortDirection: Long | ||||
|         get() = flags and SortDirectionSetting.MASK | ||||
|  | ||||
|     companion object { | ||||
|         val default = { context: Context -> | ||||
|             Category( | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.widget.ExtendedNavigationView | ||||
| import tachiyomi.source.model.MangaInfo | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import java.io.Serializable | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga as DbManga | ||||
|  | ||||
| data class Manga( | ||||
| @@ -29,7 +30,7 @@ data class Manga( | ||||
|     val status: Long, | ||||
|     val thumbnailUrl: String?, | ||||
|     val initialized: Boolean, | ||||
| ) { | ||||
| ) : Serializable { | ||||
|  | ||||
|     fun toSManga(): SManga { | ||||
|         return SManga.create().also { | ||||
|   | ||||
| @@ -2,11 +2,9 @@ package eu.kanade.tachiyomi.data.database | ||||
|  | ||||
| import androidx.sqlite.db.SupportSQLiteOpenHelper | ||||
| import com.pushtorefresh.storio.sqlite.impl.DefaultStorIOSQLite | ||||
| import eu.kanade.tachiyomi.data.database.mappers.CategoryTypeMapping | ||||
| import eu.kanade.tachiyomi.data.database.mappers.ChapterTypeMapping | ||||
| import eu.kanade.tachiyomi.data.database.mappers.MangaCategoryTypeMapping | ||||
| import eu.kanade.tachiyomi.data.database.mappers.MangaTypeMapping | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Chapter | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.MangaCategory | ||||
| @@ -26,7 +24,6 @@ class DatabaseHelper( | ||||
|         .sqliteOpenHelper(openHelper) | ||||
|         .addTypeMapping(Manga::class.java, MangaTypeMapping()) | ||||
|         .addTypeMapping(Chapter::class.java, ChapterTypeMapping()) | ||||
|         .addTypeMapping(Category::class.java, CategoryTypeMapping()) | ||||
|         .addTypeMapping(MangaCategory::class.java, MangaCategoryTypeMapping()) | ||||
|         .build() | ||||
| } | ||||
|   | ||||
| @@ -1,64 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.data.database.mappers | ||||
|  | ||||
| import android.database.Cursor | ||||
| import androidx.core.content.contentValuesOf | ||||
| import com.pushtorefresh.storio.sqlite.SQLiteTypeMapping | ||||
| import com.pushtorefresh.storio.sqlite.operations.delete.DefaultDeleteResolver | ||||
| import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver | ||||
| import com.pushtorefresh.storio.sqlite.operations.put.DefaultPutResolver | ||||
| import com.pushtorefresh.storio.sqlite.queries.DeleteQuery | ||||
| import com.pushtorefresh.storio.sqlite.queries.InsertQuery | ||||
| import com.pushtorefresh.storio.sqlite.queries.UpdateQuery | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.CategoryImpl | ||||
| import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_FLAGS | ||||
| import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ID | ||||
| import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_NAME | ||||
| import eu.kanade.tachiyomi.data.database.tables.CategoryTable.COL_ORDER | ||||
| import eu.kanade.tachiyomi.data.database.tables.CategoryTable.TABLE | ||||
|  | ||||
| class CategoryTypeMapping : SQLiteTypeMapping<Category>( | ||||
|     CategoryPutResolver(), | ||||
|     CategoryGetResolver(), | ||||
|     CategoryDeleteResolver(), | ||||
| ) | ||||
|  | ||||
| class CategoryPutResolver : DefaultPutResolver<Category>() { | ||||
|  | ||||
|     override fun mapToInsertQuery(obj: Category) = InsertQuery.builder() | ||||
|         .table(TABLE) | ||||
|         .build() | ||||
|  | ||||
|     override fun mapToUpdateQuery(obj: Category) = UpdateQuery.builder() | ||||
|         .table(TABLE) | ||||
|         .where("$COL_ID = ?") | ||||
|         .whereArgs(obj.id) | ||||
|         .build() | ||||
|  | ||||
|     override fun mapToContentValues(obj: Category) = | ||||
|         contentValuesOf( | ||||
|             COL_ID to obj.id, | ||||
|             COL_NAME to obj.name, | ||||
|             COL_ORDER to obj.order, | ||||
|             COL_FLAGS to obj.flags, | ||||
|         ) | ||||
| } | ||||
|  | ||||
| class CategoryGetResolver : DefaultGetResolver<Category>() { | ||||
|  | ||||
|     override fun mapFromCursor(cursor: Cursor): Category = CategoryImpl().apply { | ||||
|         id = cursor.getInt(cursor.getColumnIndexOrThrow(COL_ID)) | ||||
|         name = cursor.getString(cursor.getColumnIndexOrThrow(COL_NAME)) | ||||
|         order = cursor.getInt(cursor.getColumnIndexOrThrow(COL_ORDER)) | ||||
|         flags = cursor.getInt(cursor.getColumnIndexOrThrow(COL_FLAGS)) | ||||
|     } | ||||
| } | ||||
|  | ||||
| class CategoryDeleteResolver : DefaultDeleteResolver<Category>() { | ||||
|  | ||||
|     override fun mapToDeleteQuery(obj: Category) = DeleteQuery.builder() | ||||
|         .table(TABLE) | ||||
|         .where("$COL_ID = ?") | ||||
|         .whereArgs(obj.id) | ||||
|         .build() | ||||
| } | ||||
| @@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting | ||||
| import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting | ||||
| import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting | ||||
| import java.io.Serializable | ||||
| import eu.kanade.domain.category.model.Category as DomainCategory | ||||
|  | ||||
| interface Category : Serializable { | ||||
|  | ||||
| @@ -22,16 +23,16 @@ interface Category : Serializable { | ||||
|     } | ||||
|  | ||||
|     var displayMode: Int | ||||
|         get() = flags and DisplayModeSetting.MASK | ||||
|         set(mode) = setFlags(mode, DisplayModeSetting.MASK) | ||||
|         get() = flags and DisplayModeSetting.MASK.toInt() | ||||
|         set(mode) = setFlags(mode, DisplayModeSetting.MASK.toInt()) | ||||
|  | ||||
|     var sortMode: Int | ||||
|         get() = flags and SortModeSetting.MASK | ||||
|         set(mode) = setFlags(mode, SortModeSetting.MASK) | ||||
|         get() = flags and SortModeSetting.MASK.toInt() | ||||
|         set(mode) = setFlags(mode, SortModeSetting.MASK.toInt()) | ||||
|  | ||||
|     var sortDirection: Int | ||||
|         get() = flags and SortDirectionSetting.MASK | ||||
|         set(mode) = setFlags(mode, SortDirectionSetting.MASK) | ||||
|         get() = flags and SortDirectionSetting.MASK.toInt() | ||||
|         set(mode) = setFlags(mode, SortDirectionSetting.MASK.toInt()) | ||||
|  | ||||
|     companion object { | ||||
|  | ||||
| @@ -42,3 +43,13 @@ interface Category : Serializable { | ||||
|         fun createDefault(context: Context): Category = create(context.getString(R.string.label_default)).apply { id = 0 } | ||||
|     } | ||||
| } | ||||
|  | ||||
| fun Category.toDomainCategory(): DomainCategory? { | ||||
|     val categoryId = id ?: return null | ||||
|     return DomainCategory( | ||||
|         id = categoryId.toLong(), | ||||
|         name = this.name, | ||||
|         order = this.order.toLong(), | ||||
|         flags = this.flags.toLong(), | ||||
|     ) | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,8 @@ | ||||
| package eu.kanade.tachiyomi.data.database.models | ||||
|  | ||||
| import eu.kanade.domain.category.model.Category as DomainCategory | ||||
| import eu.kanade.domain.manga.model.Manga as DomainManga | ||||
|  | ||||
| class MangaCategory { | ||||
|  | ||||
|     var id: Long? = null | ||||
| @@ -10,6 +13,13 @@ class MangaCategory { | ||||
|  | ||||
|     companion object { | ||||
|  | ||||
|         fun create(manga: DomainManga, category: DomainCategory): MangaCategory { | ||||
|             val mc = MangaCategory() | ||||
|             mc.manga_id = manga.id | ||||
|             mc.category_id = category.id.toInt() | ||||
|             return mc | ||||
|         } | ||||
|  | ||||
|         fun create(manga: Manga, category: Category): MangaCategory { | ||||
|             val mc = MangaCategory() | ||||
|             mc.manga_id = manga.id!! | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| package eu.kanade.tachiyomi.data.database.queries | ||||
|  | ||||
| import eu.kanade.tachiyomi.data.database.tables.CategoryTable as Category | ||||
| import eu.kanade.tachiyomi.data.database.tables.ChapterTable as Chapter | ||||
| import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable as MangaCategory | ||||
| import eu.kanade.tachiyomi.data.database.tables.MangaTable as Manga | ||||
| @@ -36,14 +35,3 @@ val libraryQuery = | ||||
|         SELECT * FROM ${MangaCategory.TABLE}) AS MC | ||||
|         ON MC.${MangaCategory.COL_MANGA_ID} = M.${Manga.COL_ID} | ||||
| """ | ||||
|  | ||||
| /** | ||||
|  * Query to get the categories for a manga. | ||||
|  */ | ||||
| fun getCategoriesForMangaQuery() = | ||||
|     """ | ||||
|     SELECT ${Category.TABLE}.* FROM ${Category.TABLE} | ||||
|     JOIN ${MangaCategory.TABLE} ON ${Category.TABLE}.${Category.COL_ID} = | ||||
|     ${MangaCategory.TABLE}.${MangaCategory.COL_CATEGORY_ID} | ||||
|     WHERE ${MangaCategory.COL_MANGA_ID} = ? | ||||
| """ | ||||
|   | ||||
| @@ -3,12 +3,4 @@ package eu.kanade.tachiyomi.data.database.tables | ||||
| object CategoryTable { | ||||
|  | ||||
|     const val TABLE = "categories" | ||||
|  | ||||
|     const val COL_ID = "_id" | ||||
|  | ||||
|     const val COL_NAME = "name" | ||||
|  | ||||
|     const val COL_ORDER = "sort" | ||||
|  | ||||
|     const val COL_FLAGS = "flags" | ||||
| } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import android.os.PowerManager | ||||
| import androidx.core.content.ContextCompat | ||||
| import eu.kanade.data.chapter.NoChaptersException | ||||
| import eu.kanade.domain.category.interactor.GetCategories | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.domain.chapter.interactor.GetChapterByMangaId | ||||
| import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource | ||||
| import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay | ||||
| @@ -22,7 +23,6 @@ import eu.kanade.domain.track.model.toDomainTrack | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.cache.CoverCache | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Chapter | ||||
| import eu.kanade.tachiyomi.data.database.models.LibraryManga | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| @@ -228,7 +228,7 @@ class LibraryUpdateService( | ||||
|         ioScope?.cancel() | ||||
|  | ||||
|         // Update favorite manga | ||||
|         val categoryId = intent.getIntExtra(KEY_CATEGORY, -1) | ||||
|         val categoryId = intent.getLongExtra(KEY_CATEGORY, -1L) | ||||
|         addMangaToQueue(categoryId) | ||||
|  | ||||
|         // Destroy service when completed or in case of an error. | ||||
| @@ -254,11 +254,11 @@ class LibraryUpdateService( | ||||
|      * | ||||
|      * @param categoryId the ID of the category to update, or -1 if no category specified. | ||||
|      */ | ||||
|     fun addMangaToQueue(categoryId: Int) { | ||||
|     fun addMangaToQueue(categoryId: Long) { | ||||
|         val libraryManga = db.getLibraryMangas().executeAsBlocking() | ||||
|  | ||||
|         val listToUpdate = if (categoryId != -1) { | ||||
|             libraryManga.filter { it.category == categoryId } | ||||
|         val listToUpdate = if (categoryId != -1L) { | ||||
|             libraryManga.filter { it.category.toLong() == categoryId } | ||||
|         } else { | ||||
|             val categoriesToUpdate = preferences.libraryUpdateCategories().get().map(String::toInt) | ||||
|             val listToInclude = if (categoriesToUpdate.isNotEmpty()) { | ||||
|   | ||||
| @@ -9,6 +9,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.toDomainManga | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.source.CatalogueSource | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| @@ -149,6 +150,6 @@ class SearchController( | ||||
|     override fun onTitleClick(source: CatalogueSource) { | ||||
|         presenter.preferences.lastUsedSource().set(source.id) | ||||
|  | ||||
|         router.pushController(SourceSearchController(manga, source, presenter.query)) | ||||
|         router.pushController(SourceSearchController(manga?.toDomainManga(), source, presenter.query)) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -2,7 +2,8 @@ package eu.kanade.tachiyomi.ui.browse.migration.search | ||||
|  | ||||
| import android.os.Bundle | ||||
| import android.view.View | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.domain.manga.model.toDbManga | ||||
| import eu.kanade.tachiyomi.source.CatalogueSource | ||||
| import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController | ||||
| import eu.kanade.tachiyomi.ui.browse.source.browse.SourceItem | ||||
| @@ -28,7 +29,7 @@ class SourceSearchController( | ||||
|         newManga = item.manga | ||||
|         val searchController = router.backstack.findLast { it.controller.javaClass == SearchController::class.java }?.controller as SearchController? | ||||
|         val dialog = | ||||
|             SearchController.MigrationDialog(oldManga, newManga, this) | ||||
|             SearchController.MigrationDialog(oldManga?.toDbManga(), newManga?.toDbManga(), this) | ||||
|         dialog.targetController = searchController | ||||
|         dialog.showDialog(router) | ||||
|         return true | ||||
|   | ||||
| @@ -20,11 +20,11 @@ import com.google.android.material.snackbar.Snackbar | ||||
| import dev.chrisbanes.insetter.applyInsetter | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.davidea.flexibleadapter.items.IFlexible | ||||
| import eu.kanade.domain.category.model.toDbCategory | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.domain.manga.model.toDbManga | ||||
| import eu.kanade.domain.source.model.Source | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.databinding.SourceControllerBinding | ||||
| import eu.kanade.tachiyomi.source.CatalogueSource | ||||
| @@ -541,7 +541,7 @@ open class BrowseSourceController(bundle: Bundle) : | ||||
|  | ||||
|         adapter.allBoundViewHolders.forEach { holder -> | ||||
|             val item = adapter.getItem(holder.bindingAdapterPosition) as? SourceItem | ||||
|             if (item != null && item.manga.id!! == manga.id!!) { | ||||
|             if (item != null && item.manga.id == manga.id) { | ||||
|                 return holder as SourceHolder<*> | ||||
|             } | ||||
|         } | ||||
| @@ -575,7 +575,7 @@ open class BrowseSourceController(bundle: Bundle) : | ||||
|      */ | ||||
|     override fun onItemClick(view: View, position: Int): Boolean { | ||||
|         val item = adapter?.getItem(position) as? SourceItem ?: return false | ||||
|         router.pushController(MangaController(item.manga.id!!, true)) | ||||
|         router.pushController(MangaController(item.manga.id, true)) | ||||
|  | ||||
|         return false | ||||
|     } | ||||
| @@ -602,7 +602,7 @@ open class BrowseSourceController(bundle: Bundle) : | ||||
|                         .setItems(arrayOf(activity.getString(R.string.remove_from_library))) { _, which -> | ||||
|                             when (which) { | ||||
|                                 0 -> { | ||||
|                                     presenter.changeMangaFavorite(manga) | ||||
|                                     presenter.changeMangaFavorite(manga.toDbManga()) | ||||
|                                     adapter?.notifyItemChanged(position) | ||||
|                                     activity.toast(activity.getString(R.string.manga_removed_library)) | ||||
|                                 } | ||||
| @@ -637,18 +637,18 @@ open class BrowseSourceController(bundle: Bundle) : | ||||
|                 when { | ||||
|                     // Default category set | ||||
|                     defaultCategory != null -> { | ||||
|                         presenter.moveMangaToCategory(newManga, defaultCategory.toDbCategory()) | ||||
|                         presenter.moveMangaToCategory(newManga.toDbManga(), defaultCategory) | ||||
|  | ||||
|                         presenter.changeMangaFavorite(newManga) | ||||
|                         presenter.changeMangaFavorite(newManga.toDbManga()) | ||||
|                         adapter?.notifyItemChanged(position) | ||||
|                         activity.toast(activity.getString(R.string.manga_added_library)) | ||||
|                     } | ||||
|  | ||||
|                     // Automatic 'Default' or no categories | ||||
|                     defaultCategoryId == 0 || categories.isEmpty() -> { | ||||
|                         presenter.moveMangaToCategory(newManga, null) | ||||
|                         presenter.moveMangaToCategory(newManga.toDbManga(), null) | ||||
|  | ||||
|                         presenter.changeMangaFavorite(newManga) | ||||
|                         presenter.changeMangaFavorite(newManga.toDbManga()) | ||||
|                         adapter?.notifyItemChanged(position) | ||||
|                         activity.toast(activity.getString(R.string.manga_added_library)) | ||||
|                     } | ||||
| @@ -664,7 +664,7 @@ open class BrowseSourceController(bundle: Bundle) : | ||||
|                             } | ||||
|                         }.toTypedArray() | ||||
|  | ||||
|                         ChangeMangaCategoriesDialog(this@BrowseSourceController, listOf(newManga), categories.map { it.toDbCategory() }, preselected) | ||||
|                         ChangeMangaCategoriesDialog(this@BrowseSourceController, listOf(newManga), categories, preselected) | ||||
|                             .showDialog(router) | ||||
|                     } | ||||
|                 } | ||||
| @@ -681,8 +681,8 @@ open class BrowseSourceController(bundle: Bundle) : | ||||
|     override fun updateCategoriesForMangas(mangas: List<Manga>, addCategories: List<Category>, removeCategories: List<Category>) { | ||||
|         val manga = mangas.firstOrNull() ?: return | ||||
|  | ||||
|         presenter.changeMangaFavorite(manga) | ||||
|         presenter.updateMangaCategories(manga, addCategories) | ||||
|         presenter.changeMangaFavorite(manga.toDbManga()) | ||||
|         presenter.updateMangaCategories(manga.toDbManga(), addCategories) | ||||
|  | ||||
|         val position = adapter?.currentItems?.indexOfFirst { it -> (it as SourceItem).manga.id == manga.id } | ||||
|         if (position != null) { | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.browse.source.browse | ||||
| import android.os.Bundle | ||||
| import eu.davidea.flexibleadapter.items.IFlexible | ||||
| import eu.kanade.domain.category.interactor.GetCategories | ||||
| import eu.kanade.domain.category.model.toDbCategory | ||||
| import eu.kanade.domain.chapter.interactor.GetChapterByMangaId | ||||
| import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay | ||||
| import eu.kanade.domain.manga.interactor.GetDuplicateLibraryManga | ||||
| @@ -11,9 +12,9 @@ import eu.kanade.domain.track.interactor.InsertTrack | ||||
| import eu.kanade.domain.track.model.toDomainTrack | ||||
| import eu.kanade.tachiyomi.data.cache.CoverCache | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.MangaCategory | ||||
| import eu.kanade.tachiyomi.data.database.models.toDomainManga | ||||
| import eu.kanade.tachiyomi.data.database.models.toMangaInfo | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.track.EnhancedTrackService | ||||
| @@ -52,6 +53,7 @@ import kotlinx.coroutines.flow.filter | ||||
| import kotlinx.coroutines.flow.firstOrNull | ||||
| import kotlinx.coroutines.flow.map | ||||
| import kotlinx.coroutines.flow.onEach | ||||
| import kotlinx.coroutines.runBlocking | ||||
| import logcat.LogPriority | ||||
| import rx.Subscription | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| @@ -60,6 +62,7 @@ import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import java.util.Date | ||||
| import eu.kanade.domain.category.model.Category as DomainCategory | ||||
| import eu.kanade.domain.manga.model.Manga as DomainManga | ||||
|  | ||||
| open class BrowseSourcePresenter( | ||||
|     private val sourceId: Long, | ||||
| @@ -157,7 +160,7 @@ open class BrowseSourcePresenter( | ||||
|         pagerSubscription?.let { remove(it) } | ||||
|         pagerSubscription = pager.results() | ||||
|             .observeOn(Schedulers.io()) | ||||
|             .map { (first, second) -> first to second.map { networkToLocalManga(it, sourceId) } } | ||||
|             .map { (first, second) -> first to second.map { networkToLocalManga(it, sourceId).toDomainManga()!! } } | ||||
|             .doOnNext { initializeMangas(it.second) } | ||||
|             .map { (first, second) -> first to second.map { SourceItem(it, sourceDisplayMode) } } | ||||
|             .observeOn(AndroidSchedulers.mainThread()) | ||||
| @@ -225,15 +228,15 @@ open class BrowseSourcePresenter( | ||||
|      * | ||||
|      * @param mangas the list of manga to initialize. | ||||
|      */ | ||||
|     fun initializeMangas(mangas: List<Manga>) { | ||||
|     fun initializeMangas(mangas: List<DomainManga>) { | ||||
|         presenterScope.launchIO { | ||||
|             mangas.asFlow() | ||||
|                 .filter { it.thumbnail_url == null && !it.initialized } | ||||
|                 .map { getMangaDetails(it) } | ||||
|                 .filter { it.thumbnailUrl == null && !it.initialized } | ||||
|                 .map { getMangaDetails(it.toDbManga()) } | ||||
|                 .onEach { | ||||
|                     withUIContext { | ||||
|                         @Suppress("DEPRECATION") | ||||
|                         view?.onMangaInitialized(it) | ||||
|                         view?.onMangaInitialized(it.toDomainManga()!!) | ||||
|                     } | ||||
|                 } | ||||
|                 .catch { e -> logcat(LogPriority.ERROR, e) } | ||||
| @@ -362,8 +365,8 @@ open class BrowseSourcePresenter( | ||||
|         return getCategories.subscribe().firstOrNull() ?: emptyList() | ||||
|     } | ||||
|  | ||||
|     suspend fun getDuplicateLibraryManga(manga: Manga): Manga? { | ||||
|         return getDuplicateLibraryManga.await(manga.title, manga.source)?.toDbManga() | ||||
|     suspend fun getDuplicateLibraryManga(manga: DomainManga): DomainManga? { | ||||
|         return getDuplicateLibraryManga.await(manga.title, manga.source) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -372,9 +375,10 @@ open class BrowseSourcePresenter( | ||||
|      * @param manga the manga to get categories from. | ||||
|      * @return Array of category ids the manga is in, if none returns default id | ||||
|      */ | ||||
|     suspend fun getMangaCategoryIds(manga: Manga): Array<Long?> { | ||||
|         val categories = getCategories.await(manga.id!!) | ||||
|         return categories.map { it.id }.toTypedArray() | ||||
|     fun getMangaCategoryIds(manga: DomainManga): Array<Long?> { | ||||
|         return runBlocking { getCategories.await(manga.id) } | ||||
|             .map { it.id } | ||||
|             .toTypedArray() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -383,8 +387,8 @@ open class BrowseSourcePresenter( | ||||
|      * @param categories the selected categories. | ||||
|      * @param manga the manga to move. | ||||
|      */ | ||||
|     private fun moveMangaToCategories(manga: Manga, categories: List<Category>) { | ||||
|         val mc = categories.filter { it.id != 0 }.map { MangaCategory.create(manga, it) } | ||||
|     private fun moveMangaToCategories(manga: Manga, categories: List<DomainCategory>) { | ||||
|         val mc = categories.filter { it.id != 0L }.map { MangaCategory.create(manga, it.toDbCategory()) } | ||||
|         db.setMangaCategories(mc, listOf(manga)) | ||||
|     } | ||||
|  | ||||
| @@ -394,7 +398,7 @@ open class BrowseSourcePresenter( | ||||
|      * @param category the selected category. | ||||
|      * @param manga the manga to move. | ||||
|      */ | ||||
|     fun moveMangaToCategory(manga: Manga, category: Category?) { | ||||
|     fun moveMangaToCategory(manga: Manga, category: DomainCategory?) { | ||||
|         moveMangaToCategories(manga, listOfNotNull(category)) | ||||
|     } | ||||
|  | ||||
| @@ -404,7 +408,7 @@ open class BrowseSourcePresenter( | ||||
|      * @param manga needed to change | ||||
|      * @param selectedCategories selected categories | ||||
|      */ | ||||
|     fun updateMangaCategories(manga: Manga, selectedCategories: List<Category>) { | ||||
|     fun updateMangaCategories(manga: Manga, selectedCategories: List<DomainCategory>) { | ||||
|         if (!manga.favorite) { | ||||
|             changeMangaFavorite(manga) | ||||
|         } | ||||
|   | ||||
| @@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.browse.source.browse | ||||
| import androidx.core.view.isVisible | ||||
| import coil.dispose | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding | ||||
| import eu.kanade.tachiyomi.util.view.loadAutoPause | ||||
|  | ||||
|   | ||||
| @@ -3,8 +3,8 @@ package eu.kanade.tachiyomi.ui.browse.source.browse | ||||
| import androidx.core.view.isVisible | ||||
| import coil.dispose | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding | ||||
| import eu.kanade.tachiyomi.util.view.loadAutoPause | ||||
|  | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import android.view.View | ||||
| import androidx.viewbinding.ViewBinding | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.davidea.viewholders.FlexibleViewHolder | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
|  | ||||
| /** | ||||
|  * Generic class used to hold the displayed data of a manga in the catalogue. | ||||
|   | ||||
| @@ -6,8 +6,8 @@ import com.fredporciuncula.flow.preferences.Preference | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.davidea.flexibleadapter.items.AbstractFlexibleItem | ||||
| import eu.davidea.flexibleadapter.items.IFlexible | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding | ||||
| import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding | ||||
| import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting | ||||
|   | ||||
| @@ -5,9 +5,9 @@ import androidx.core.view.isVisible | ||||
| import coil.dispose | ||||
| import coil.load | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.coil.MangaCoverFetcher | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.databinding.SourceListItemBinding | ||||
| import eu.kanade.tachiyomi.util.system.getResourceColor | ||||
|  | ||||
| @@ -51,7 +51,7 @@ class SourceListHolder(private val view: View, adapter: FlexibleAdapter<*>) : | ||||
|  | ||||
|     override fun setImage(manga: Manga) { | ||||
|         binding.thumbnail.dispose() | ||||
|         if (!manga.thumbnail_url.isNullOrEmpty()) { | ||||
|         if (!manga.thumbnailUrl.isNullOrEmpty()) { | ||||
|             binding.thumbnail.load(manga) { | ||||
|                 setParameter(MangaCoverFetcher.USE_CUSTOM_COVER, false) | ||||
|             } | ||||
|   | ||||
| @@ -4,9 +4,9 @@ import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.pushController | ||||
| import eu.kanade.tachiyomi.ui.category.CategoryController | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.ui.library | ||||
| import android.view.LayoutInflater | ||||
| import android.view.View | ||||
| import android.view.ViewGroup | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.databinding.LibraryCategoryBinding | ||||
| import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting | ||||
| @@ -153,7 +153,7 @@ class LibraryAdapter( | ||||
|  | ||||
|     override fun getViewType(position: Int): Int { | ||||
|         val category = categories.getOrNull(position) | ||||
|         return if (isPerCategory && category?.id != 0) { | ||||
|         return if (isPerCategory && category?.id != 0L) { | ||||
|             if (DisplayModeSetting.fromFlag(category?.displayMode) == DisplayModeSetting.LIST) { | ||||
|                 LIST_DISPLAY_MODE | ||||
|             } else { | ||||
|   | ||||
| @@ -8,8 +8,8 @@ import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import dev.chrisbanes.insetter.applyInsetter | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.davidea.flexibleadapter.SelectableAdapter | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateService | ||||
| import eu.kanade.tachiyomi.databinding.LibraryCategoryBinding | ||||
|   | ||||
| @@ -15,9 +15,11 @@ import com.fredporciuncula.flow.preferences.Preference | ||||
| import com.google.android.material.tabs.TabLayout | ||||
| import com.jakewharton.rxrelay.BehaviorRelay | ||||
| import com.jakewharton.rxrelay.PublishRelay | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.domain.category.model.toDbCategory | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.toDomainManga | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateService | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.databinding.LibraryControllerBinding | ||||
| @@ -50,6 +52,7 @@ import rx.android.schedulers.AndroidSchedulers | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import java.util.concurrent.TimeUnit | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga as DbManga | ||||
|  | ||||
| class LibraryController( | ||||
|     bundle: Bundle? = null, | ||||
| @@ -74,7 +77,7 @@ class LibraryController( | ||||
|     /** | ||||
|      * Currently selected mangas. | ||||
|      */ | ||||
|     val selectedMangas = mutableSetOf<Manga>() | ||||
|     val selectedMangas = mutableSetOf<DbManga>() | ||||
|  | ||||
|     /** | ||||
|      * Relay to notify the UI of selection updates. | ||||
| @@ -94,12 +97,12 @@ class LibraryController( | ||||
|     /** | ||||
|      * Relay to notify the library's viewpager to select all manga | ||||
|      */ | ||||
|     val selectAllRelay: PublishRelay<Int> = PublishRelay.create() | ||||
|     val selectAllRelay: PublishRelay<Long> = PublishRelay.create() | ||||
|  | ||||
|     /** | ||||
|      * Relay to notify the library's viewpager to select the inverse | ||||
|      */ | ||||
|     val selectInverseRelay: PublishRelay<Int> = PublishRelay.create() | ||||
|     val selectInverseRelay: PublishRelay<Long> = PublishRelay.create() | ||||
|  | ||||
|     /** | ||||
|      * Number of manga per row in grid mode. | ||||
| @@ -262,14 +265,14 @@ class LibraryController( | ||||
|     fun showSettingsSheet() { | ||||
|         if (adapter?.categories?.isNotEmpty() == true) { | ||||
|             adapter?.categories?.get(binding.libraryPager.currentItem)?.let { category -> | ||||
|                 settingsSheet?.show(category) | ||||
|                 settingsSheet?.show(category.toDbCategory()) | ||||
|             } | ||||
|         } else { | ||||
|             settingsSheet?.show() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun onNextLibraryUpdate(categories: List<Category>, mangaMap: Map<Int, List<LibraryItem>>) { | ||||
|     fun onNextLibraryUpdate(categories: List<Category>, mangaMap: LibraryMap) { | ||||
|         val view = view ?: return | ||||
|         val adapter = adapter ?: return | ||||
|  | ||||
| @@ -344,7 +347,7 @@ class LibraryController( | ||||
|         if (!firstLaunch) { | ||||
|             mangaCountVisibilityRelay.call(preferences.categoryNumberOfItems().get()) | ||||
|         } | ||||
|         tabsVisibilityRelay.call(preferences.categoryTabs().get() && adapter?.categories?.size ?: 0 > 1) | ||||
|         tabsVisibilityRelay.call(preferences.categoryTabs().get() && (adapter?.categories?.size ?: 0) > 1) | ||||
|         updateTitle() | ||||
|     } | ||||
|  | ||||
| @@ -493,7 +496,7 @@ class LibraryController( | ||||
|         actionMode = null | ||||
|     } | ||||
|  | ||||
|     fun openManga(manga: Manga) { | ||||
|     fun openManga(manga: DbManga) { | ||||
|         // Notify the presenter a manga is being opened. | ||||
|         presenter.onOpenManga() | ||||
|  | ||||
| @@ -506,7 +509,7 @@ class LibraryController( | ||||
|      * @param manga the manga whose selection has changed. | ||||
|      * @param selected whether it's now selected or not. | ||||
|      */ | ||||
|     fun setSelection(manga: Manga, selected: Boolean) { | ||||
|     fun setSelection(manga: DbManga, selected: Boolean) { | ||||
|         if (selected) { | ||||
|             if (selectedMangas.add(manga)) { | ||||
|                 selectionRelay.call(LibrarySelectionEvent.Selected(manga)) | ||||
| @@ -523,7 +526,7 @@ class LibraryController( | ||||
|      * | ||||
|      * @param manga the manga whose selection to change. | ||||
|      */ | ||||
|     fun toggleSelection(manga: Manga) { | ||||
|     fun toggleSelection(manga: DbManga) { | ||||
|         if (selectedMangas.add(manga)) { | ||||
|             selectionRelay.call(LibrarySelectionEvent.Selected(manga)) | ||||
|         } else if (selectedMangas.remove(manga)) { | ||||
| @@ -550,7 +553,7 @@ class LibraryController( | ||||
|             val mangas = selectedMangas.toList() | ||||
|  | ||||
|             // Hide the default category because it has a different behavior than the ones from db. | ||||
|             val categories = presenter.categories.filter { it.id != 0 } | ||||
|             val categories = presenter.categories.filter { it.id != 0L } | ||||
|  | ||||
|             // Get indexes of the common categories to preselect. | ||||
|             val common = presenter.getCommonCategories(mangas) | ||||
| @@ -564,7 +567,7 @@ class LibraryController( | ||||
|                 } | ||||
|             }.toTypedArray() | ||||
|             launchUI { | ||||
|                 ChangeMangaCategoriesDialog(this@LibraryController, mangas, categories, preselected) | ||||
|                 ChangeMangaCategoriesDialog(this@LibraryController, mangas.map { it.toDomainManga()!! }, categories, preselected) | ||||
|                     .showDialog(router) | ||||
|             } | ||||
|         } | ||||
| @@ -591,7 +594,7 @@ class LibraryController( | ||||
|         destroyActionModeIfNeeded() | ||||
|     } | ||||
|  | ||||
|     override fun deleteMangas(mangas: List<Manga>, deleteFromLibrary: Boolean, deleteChapters: Boolean) { | ||||
|     override fun deleteMangas(mangas: List<DbManga>, deleteFromLibrary: Boolean, deleteChapters: Boolean) { | ||||
|         presenter.removeMangas(mangas, deleteFromLibrary, deleteChapters) | ||||
|         destroyActionModeIfNeeded() | ||||
|     } | ||||
|   | ||||
| @@ -25,7 +25,7 @@ class LibraryItem( | ||||
|  | ||||
|     private val sourceManager: SourceManager = Injekt.get() | ||||
|  | ||||
|     var displayMode: Int = -1 | ||||
|     var displayMode: Long = -1 | ||||
|     var downloadCount = -1 | ||||
|     var unreadCount = -1 | ||||
|     var isLocal = false | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| package eu.kanade.tachiyomi.ui.library | ||||
|  | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.domain.category.model.Category | ||||
|  | ||||
| class LibraryMangaEvent(val mangas: Map<Int, List<LibraryItem>>) { | ||||
| class LibraryMangaEvent(val mangas: LibraryMap) { | ||||
|  | ||||
|     fun getMangaForCategory(category: Category): List<LibraryItem>? { | ||||
|         return mangas[category.id] | ||||
|   | ||||
| @@ -6,19 +6,18 @@ import eu.kanade.core.util.asObservable | ||||
| import eu.kanade.data.DatabaseHandler | ||||
| import eu.kanade.domain.category.interactor.GetCategories | ||||
| import eu.kanade.domain.category.interactor.SetMangaCategories | ||||
| import eu.kanade.domain.category.model.toDbCategory | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.domain.chapter.interactor.GetChapterByMangaId | ||||
| import eu.kanade.domain.chapter.interactor.UpdateChapter | ||||
| import eu.kanade.domain.chapter.model.ChapterUpdate | ||||
| import eu.kanade.domain.chapter.model.toDbChapter | ||||
| import eu.kanade.domain.manga.interactor.UpdateManga | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.domain.manga.model.MangaUpdate | ||||
| import eu.kanade.domain.track.interactor.GetTracks | ||||
| import eu.kanade.tachiyomi.data.cache.CoverCache | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Chapter | ||||
| import eu.kanade.tachiyomi.data.database.models.LibraryManga | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.download.DownloadManager | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| @@ -34,7 +33,6 @@ import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed | ||||
| import eu.kanade.tachiyomi.util.lang.launchIO | ||||
| import eu.kanade.tachiyomi.util.removeCovers | ||||
| import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State | ||||
| import kotlinx.coroutines.flow.map | ||||
| import kotlinx.coroutines.runBlocking | ||||
| import rx.Observable | ||||
| import rx.Subscription | ||||
| @@ -45,6 +43,7 @@ import uy.kohesive.injekt.api.get | ||||
| import java.text.Collator | ||||
| import java.util.Collections | ||||
| import java.util.Locale | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga as DbManga | ||||
|  | ||||
| /** | ||||
|  * Class containing library information. | ||||
| @@ -54,7 +53,7 @@ private data class Library(val categories: List<Category>, val mangaMap: Library | ||||
| /** | ||||
|  * Typealias for the library manga, using the category as keys, and list of manga as values. | ||||
|  */ | ||||
| private typealias LibraryMap = Map<Int, List<LibraryItem>> | ||||
| typealias LibraryMap = Map<Long, List<LibraryItem>> | ||||
|  | ||||
| /** | ||||
|  * Presenter of [LibraryController]. | ||||
| @@ -299,11 +298,11 @@ class LibraryPresenter( | ||||
|         } | ||||
|  | ||||
|         val sortingModes = categories.associate { category -> | ||||
|             (category.id ?: 0) to SortModeSetting.get(preferences, category) | ||||
|             category.id to SortModeSetting.get(preferences, category) | ||||
|         } | ||||
|  | ||||
|         val sortDirections = categories.associate { category -> | ||||
|             (category.id ?: 0) to SortDirectionSetting.get(preferences, category) | ||||
|             category.id to SortDirectionSetting.get(preferences, category) | ||||
|         } | ||||
|  | ||||
|         val locale = Locale.getDefault() | ||||
| @@ -311,8 +310,8 @@ class LibraryPresenter( | ||||
|             strength = Collator.PRIMARY | ||||
|         } | ||||
|         val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> | ||||
|             val sortingMode = sortingModes[i1.manga.category]!! | ||||
|             val sortAscending = sortDirections[i1.manga.category]!! == SortDirectionSetting.ASCENDING | ||||
|             val sortingMode = sortingModes[i1.manga.category.toLong()]!! | ||||
|             val sortAscending = sortDirections[i1.manga.category.toLong()]!! == SortDirectionSetting.ASCENDING | ||||
|             when (sortingMode) { | ||||
|                 SortModeSetting.ALPHABETICAL -> { | ||||
|                     collator.compare(i1.manga.title.lowercase(locale), i2.manga.title.lowercase(locale)) | ||||
| @@ -355,7 +354,7 @@ class LibraryPresenter( | ||||
|         } | ||||
|  | ||||
|         return map.mapValues { entry -> | ||||
|             val sortAscending = sortDirections[entry.key]!! == SortDirectionSetting.ASCENDING | ||||
|             val sortAscending = sortDirections[entry.key.toLong()]!! == SortDirectionSetting.ASCENDING | ||||
|  | ||||
|             val comparator = if (sortAscending) { | ||||
|                 Comparator(sortFn) | ||||
| @@ -375,13 +374,13 @@ class LibraryPresenter( | ||||
|     private fun getLibraryObservable(): Observable<Library> { | ||||
|         return Observable.combineLatest(getCategoriesObservable(), getLibraryMangasObservable()) { dbCategories, libraryManga -> | ||||
|             val categories = if (libraryManga.containsKey(0)) { | ||||
|                 arrayListOf(Category.createDefault(context)) + dbCategories | ||||
|                 arrayListOf(Category.default(context)) + dbCategories | ||||
|             } else { | ||||
|                 dbCategories | ||||
|             } | ||||
|  | ||||
|             libraryManga.forEach { (categoryId, libraryManga) -> | ||||
|                 val category = categories.first { category -> category.id == categoryId } | ||||
|                 val category = categories.first { category -> category.id == categoryId.toLong() } | ||||
|                 libraryManga.forEach { libraryItem -> | ||||
|                     libraryItem.displayMode = category.displayMode | ||||
|                 } | ||||
| @@ -398,7 +397,7 @@ class LibraryPresenter( | ||||
|      * @return an observable of the categories. | ||||
|      */ | ||||
|     private fun getCategoriesObservable(): Observable<List<Category>> { | ||||
|         return getCategories.subscribe().map { it.map { it.toDbCategory() } }.asObservable() | ||||
|         return getCategories.subscribe().asObservable() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -448,7 +447,7 @@ class LibraryPresenter( | ||||
|                         shouldSetFromCategory, | ||||
|                         defaultLibraryDisplayMode, | ||||
|                     ) | ||||
|                 }.groupBy { it.manga.category } | ||||
|                 }.groupBy { it.manga.category.toLong() } | ||||
|             } | ||||
|     } | ||||
|  | ||||
| @@ -516,10 +515,10 @@ class LibraryPresenter( | ||||
|      * | ||||
|      * @param mangas the list of manga. | ||||
|      */ | ||||
|     suspend fun getCommonCategories(mangas: List<Manga>): Collection<Category> { | ||||
|     suspend fun getCommonCategories(mangas: List<DbManga>): Collection<Category> { | ||||
|         if (mangas.isEmpty()) return emptyList() | ||||
|         return mangas.toSet() | ||||
|             .map { getCategories.await(it.id!!).map { it.toDbCategory() } } | ||||
|             .map { getCategories.await(it.id!!) } | ||||
|             .reduce { set1, set2 -> set1.intersect(set2).toMutableList() } | ||||
|     } | ||||
|  | ||||
| @@ -528,9 +527,9 @@ class LibraryPresenter( | ||||
|      * | ||||
|      * @param mangas the list of manga. | ||||
|      */ | ||||
|     suspend fun getMixCategories(mangas: List<Manga>): Collection<Category> { | ||||
|     suspend fun getMixCategories(mangas: List<DbManga>): Collection<Category> { | ||||
|         if (mangas.isEmpty()) return emptyList() | ||||
|         val mangaCategories = mangas.toSet().map { getCategories.await(it.id!!).map { it.toDbCategory() } } | ||||
|         val mangaCategories = mangas.toSet().map { getCategories.await(it.id!!) } | ||||
|         val common = mangaCategories.reduce { set1, set2 -> set1.intersect(set2).toMutableList() } | ||||
|         return mangaCategories.flatten().distinct().subtract(common).toMutableList() | ||||
|     } | ||||
| @@ -540,7 +539,7 @@ class LibraryPresenter( | ||||
|      * | ||||
|      * @param mangas the list of manga. | ||||
|      */ | ||||
|     fun downloadUnreadChapters(mangas: List<Manga>) { | ||||
|     fun downloadUnreadChapters(mangas: List<DbManga>) { | ||||
|         mangas.forEach { manga -> | ||||
|             launchIO { | ||||
|                 val chapters = getChapterByMangaId.await(manga.id!!) | ||||
| @@ -557,7 +556,7 @@ class LibraryPresenter( | ||||
|      * | ||||
|      * @param mangas the list of manga. | ||||
|      */ | ||||
|     fun markReadStatus(mangas: List<Manga>, read: Boolean) { | ||||
|     fun markReadStatus(mangas: List<DbManga>, read: Boolean) { | ||||
|         mangas.forEach { manga -> | ||||
|             launchIO { | ||||
|                 val chapters = getChapterByMangaId.await(manga.id!!) | ||||
| @@ -579,7 +578,7 @@ class LibraryPresenter( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun deleteChapters(manga: Manga, chapters: List<Chapter>) { | ||||
|     private fun deleteChapters(manga: DbManga, chapters: List<Chapter>) { | ||||
|         sourceManager.get(manga.source)?.let { source -> | ||||
|             downloadManager.deleteChapters(chapters, manga, source) | ||||
|         } | ||||
| @@ -592,7 +591,7 @@ class LibraryPresenter( | ||||
|      * @param deleteFromLibrary whether to delete manga from library. | ||||
|      * @param deleteChapters whether to delete downloaded chapters. | ||||
|      */ | ||||
|     fun removeMangas(mangaList: List<Manga>, deleteFromLibrary: Boolean, deleteChapters: Boolean) { | ||||
|     fun removeMangas(mangaList: List<DbManga>, deleteFromLibrary: Boolean, deleteChapters: Boolean) { | ||||
|         launchIO { | ||||
|             val mangaToDelete = mangaList.distinctBy { it.id } | ||||
|  | ||||
| @@ -628,12 +627,11 @@ class LibraryPresenter( | ||||
|     fun setMangaCategories(mangaList: List<Manga>, addCategories: List<Category>, removeCategories: List<Category>) { | ||||
|         presenterScope.launchIO { | ||||
|             mangaList.map { manga -> | ||||
|                 val categoryIds = getCategories.await(manga.id!!) | ||||
|                     .map { it.toDbCategory() } | ||||
|                 val categoryIds = getCategories.await(manga.id) | ||||
|                     .subtract(removeCategories) | ||||
|                     .plus(addCategories) | ||||
|                     .mapNotNull { it.id?.toLong() } | ||||
|                 setMangaCategories.await(manga.id!!, categoryIds) | ||||
|                     .map { it.id } | ||||
|                 setMangaCategories.await(manga.id, categoryIds) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import eu.kanade.domain.category.interactor.UpdateCategory | ||||
| import eu.kanade.domain.category.model.CategoryUpdate | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.toDomainCategory | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.data.track.TrackService | ||||
| @@ -201,8 +202,8 @@ class LibrarySettingsSheet( | ||||
|             override val footer = null | ||||
|  | ||||
|             override fun initModels() { | ||||
|                 val sorting = SortModeSetting.get(preferences, currentCategory) | ||||
|                 val order = if (SortDirectionSetting.get(preferences, currentCategory) == SortDirectionSetting.ASCENDING) { | ||||
|                 val sorting = SortModeSetting.get(preferences, currentCategory?.toDomainCategory()) | ||||
|                 val order = if (SortDirectionSetting.get(preferences, currentCategory?.toDomainCategory()) == SortDirectionSetting.ASCENDING) { | ||||
|                     Item.MultiSort.SORT_ASC | ||||
|                 } else { | ||||
|                     Item.MultiSort.SORT_DESC | ||||
| @@ -243,12 +244,12 @@ class LibrarySettingsSheet( | ||||
|  | ||||
|                 setSortModePreference(item) | ||||
|  | ||||
|                 setSortDirectionPrefernece(item) | ||||
|                 setSortDirectionPreference(item) | ||||
|  | ||||
|                 item.group.items.forEach { adapter.notifyItemChanged(it) } | ||||
|             } | ||||
|  | ||||
|             private fun setSortDirectionPrefernece(item: Item.MultiStateGroup) { | ||||
|             private fun setSortDirectionPreference(item: Item.MultiStateGroup) { | ||||
|                 val flag = if (item.state == Item.MultiSort.SORT_ASC) { | ||||
|                     SortDirectionSetting.ASCENDING | ||||
|                 } else { | ||||
| @@ -256,7 +257,7 @@ class LibrarySettingsSheet( | ||||
|                 } | ||||
|  | ||||
|                 if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) { | ||||
|                     currentCategory?.sortDirection = flag.flag | ||||
|                     currentCategory?.sortDirection = flag.flag.toInt() | ||||
|                     sheetScope.launchIO { | ||||
|                         updateCategory.await( | ||||
|                             CategoryUpdate( | ||||
| @@ -284,7 +285,7 @@ class LibrarySettingsSheet( | ||||
|                 } | ||||
|  | ||||
|                 if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) { | ||||
|                     currentCategory?.sortMode = flag.flag | ||||
|                     currentCategory?.sortMode = flag.flag.toInt() | ||||
|                     sheetScope.launchIO { | ||||
|                         updateCategory.await( | ||||
|                             CategoryUpdate( | ||||
| @@ -327,7 +328,7 @@ class LibrarySettingsSheet( | ||||
|         // Gets user preference of currently selected display mode at current category | ||||
|         private fun getDisplayModePreference(): DisplayModeSetting { | ||||
|             return if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) { | ||||
|                 DisplayModeSetting.fromFlag(currentCategory?.displayMode) | ||||
|                 DisplayModeSetting.fromFlag(currentCategory?.displayMode?.toLong()) | ||||
|             } else { | ||||
|                 preferences.libraryDisplayMode().get() | ||||
|             } | ||||
| @@ -379,7 +380,7 @@ class LibrarySettingsSheet( | ||||
|                 } | ||||
|  | ||||
|                 if (preferences.categorizedDisplaySettings().get() && currentCategory != null && currentCategory?.id != 0) { | ||||
|                     currentCategory?.displayMode = flag.flag | ||||
|                     currentCategory?.displayMode = flag.flag.toInt() | ||||
|                     sheetScope.launchIO { | ||||
|                         updateCategory.await( | ||||
|                             CategoryUpdate( | ||||
|   | ||||
| @@ -1,15 +1,15 @@ | ||||
| package eu.kanade.tachiyomi.ui.library.setting | ||||
|  | ||||
| enum class DisplayModeSetting(val flag: Int) { | ||||
| enum class DisplayModeSetting(val flag: Long) { | ||||
|     COMPACT_GRID(0b00000000), | ||||
|     COMFORTABLE_GRID(0b00000001), | ||||
|     LIST(0b00000010), | ||||
|     COVER_ONLY_GRID(0b00000011); | ||||
|  | ||||
|     companion object { | ||||
|         const val MASK = 0b00000011 | ||||
|         const val MASK = 0b00000011L | ||||
|  | ||||
|         fun fromFlag(flag: Int?): DisplayModeSetting { | ||||
|         fun fromFlag(flag: Long?): DisplayModeSetting { | ||||
|             return values() | ||||
|                 .find { mode -> mode.flag == flag } ?: COMPACT_GRID | ||||
|         } | ||||
|   | ||||
| @@ -1,21 +1,21 @@ | ||||
| package eu.kanade.tachiyomi.ui.library.setting | ||||
|  | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
|  | ||||
| enum class SortDirectionSetting(val flag: Int) { | ||||
| enum class SortDirectionSetting(val flag: Long) { | ||||
|     ASCENDING(0b01000000), | ||||
|     DESCENDING(0b00000000); | ||||
|  | ||||
|     companion object { | ||||
|         const val MASK = 0b01000000 | ||||
|         const val MASK = 0b01000000L | ||||
|  | ||||
|         fun fromFlag(flag: Int?): SortDirectionSetting { | ||||
|         fun fromFlag(flag: Long?): SortDirectionSetting { | ||||
|             return values().find { mode -> mode.flag == flag } ?: ASCENDING | ||||
|         } | ||||
|  | ||||
|         fun get(preferences: PreferencesHelper, category: Category?): SortDirectionSetting { | ||||
|             return if (preferences.categorizedDisplaySettings().get() && category != null && category.id != 0) { | ||||
|             return if (preferences.categorizedDisplaySettings().get() && category != null && category.id != 0L) { | ||||
|                 fromFlag(category.sortDirection) | ||||
|             } else { | ||||
|                 preferences.librarySortingAscending().get() | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| package eu.kanade.tachiyomi.ui.library.setting | ||||
|  | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
|  | ||||
| enum class SortModeSetting(val flag: Int) { | ||||
| enum class SortModeSetting(val flag: Long) { | ||||
|     ALPHABETICAL(0b00000000), | ||||
|     LAST_READ(0b00000100), | ||||
|     LAST_MANGA_UPDATE(0b00001000), | ||||
| @@ -25,14 +25,14 @@ enum class SortModeSetting(val flag: Int) { | ||||
|  | ||||
|     companion object { | ||||
|         // Mask supports for more sorting flags if necessary | ||||
|         const val MASK = 0b00111100 | ||||
|         const val MASK = 0b00111100L | ||||
|  | ||||
|         fun fromFlag(flag: Int?): SortModeSetting { | ||||
|         fun fromFlag(flag: Long?): SortModeSetting { | ||||
|             return values().find { mode -> mode.flag == flag } ?: ALPHABETICAL | ||||
|         } | ||||
|  | ||||
|         fun get(preferences: PreferencesHelper, category: Category?): SortModeSetting { | ||||
|             return if (preferences.categorizedDisplaySettings().get() && category != null && category.id != 0) { | ||||
|             return if (preferences.categorizedDisplaySettings().get() && category != null && category.id != 0L) { | ||||
|                 fromFlag(category.sortMode) | ||||
|             } else { | ||||
|                 preferences.librarySortingMode().get() | ||||
|   | ||||
| @@ -4,8 +4,8 @@ import android.app.Dialog | ||||
| import android.os.Bundle | ||||
| import com.bluelinelabs.conductor.Controller | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.source.SourceManager | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.pushController | ||||
|   | ||||
| @@ -24,14 +24,14 @@ import com.bluelinelabs.conductor.ControllerChangeHandler | ||||
| import com.bluelinelabs.conductor.ControllerChangeType | ||||
| import com.google.android.material.dialog.MaterialAlertDialogBuilder | ||||
| import eu.kanade.data.chapter.NoChaptersException | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.domain.manga.model.Manga | ||||
| import eu.kanade.domain.manga.model.toDbManga | ||||
| import eu.kanade.presentation.manga.ChapterDownloadAction | ||||
| import eu.kanade.presentation.manga.DownloadAction | ||||
| import eu.kanade.presentation.manga.MangaScreen | ||||
| import eu.kanade.presentation.util.calculateWindowWidthSizeClass | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.download.DownloadService | ||||
| import eu.kanade.tachiyomi.data.download.model.Download | ||||
| import eu.kanade.tachiyomi.data.track.model.TrackSearch | ||||
| @@ -59,7 +59,7 @@ import eu.kanade.tachiyomi.ui.recent.history.HistoryController | ||||
| import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController | ||||
| import eu.kanade.tachiyomi.ui.webview.WebViewActivity | ||||
| import eu.kanade.tachiyomi.util.lang.launchIO | ||||
| import eu.kanade.tachiyomi.util.lang.launchUI | ||||
| import eu.kanade.tachiyomi.util.lang.withUIContext | ||||
| import eu.kanade.tachiyomi.util.system.logcat | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import eu.kanade.tachiyomi.widget.materialdialogs.QuadStateTextView | ||||
| @@ -211,7 +211,7 @@ class MangaController : | ||||
|                 { | ||||
|                     AddDuplicateMangaDialog( | ||||
|                         target = this, | ||||
|                         libraryManga = it.toDbManga(), | ||||
|                         libraryManga = it, | ||||
|                         onAddToLibrary = { onFavoriteClick(checkDuplicate = false) }, | ||||
|                     ).showDialog(router) | ||||
|                 } | ||||
| @@ -225,7 +225,7 @@ class MangaController : | ||||
|                         QuadStateTextView.State.UNCHECKED.ordinal | ||||
|                     } | ||||
|                 }.toTypedArray() | ||||
|                 showChangeCategoryDialog(manga.toDbManga(), categories, preselected) | ||||
|                 showChangeCategoryDialog(manga, categories, preselected) | ||||
|             }, | ||||
|         ) | ||||
|     } | ||||
| @@ -246,10 +246,6 @@ class MangaController : | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun onTrackingClick() { | ||||
|         trackSheet.show() | ||||
|     } | ||||
|  | ||||
|     private fun onCategoriesClick() { | ||||
|         viewScope.launchIO { | ||||
|             val manga = presenter.manga ?: return@launchIO | ||||
| @@ -263,8 +259,9 @@ class MangaController : | ||||
|                     QuadStateTextView.State.UNCHECKED.ordinal | ||||
|                 } | ||||
|             }.toTypedArray() | ||||
|             launchUI { | ||||
|                 showChangeCategoryDialog(manga.toDbManga(), categories, preselected) | ||||
|  | ||||
|             withUIContext { | ||||
|                 showChangeCategoryDialog(manga, categories, preselected) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import android.os.Bundle | ||||
| import androidx.compose.runtime.Immutable | ||||
| import eu.kanade.domain.category.interactor.GetCategories | ||||
| import eu.kanade.domain.category.interactor.SetMangaCategories | ||||
| import eu.kanade.domain.category.model.toDbCategory | ||||
| import eu.kanade.domain.category.model.Category | ||||
| import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource | ||||
| import eu.kanade.domain.chapter.interactor.SyncChaptersWithTrackServiceTwoWay | ||||
| import eu.kanade.domain.chapter.interactor.UpdateChapter | ||||
| @@ -23,9 +23,7 @@ import eu.kanade.domain.track.interactor.GetTracks | ||||
| import eu.kanade.domain.track.interactor.InsertTrack | ||||
| import eu.kanade.domain.track.model.toDbTrack | ||||
| import eu.kanade.domain.track.model.toDomainTrack | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Chapter | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
| import eu.kanade.tachiyomi.data.database.models.toDomainChapter | ||||
| import eu.kanade.tachiyomi.data.download.DownloadManager | ||||
| @@ -258,22 +256,22 @@ class MangaPresenter( | ||||
|  | ||||
|                 // Now check if user previously set categories, when available | ||||
|                 val categories = getCategories() | ||||
|                 val defaultCategoryId = preferences.defaultCategory() | ||||
|                 val defaultCategoryId = preferences.defaultCategory().toLong() | ||||
|                 val defaultCategory = categories.find { it.id == defaultCategoryId } | ||||
|                 when { | ||||
|                     // Default category set | ||||
|                     defaultCategory != null -> { | ||||
|                         val result = updateManga.awaitUpdateFavorite(manga.id, true) | ||||
|                         if (!result) return@launchIO | ||||
|                         moveMangaToCategory(manga.toDbManga(), defaultCategory) | ||||
|                         moveMangaToCategory(defaultCategory) | ||||
|                         launchUI { onAdded() } | ||||
|                     } | ||||
|  | ||||
|                     // Automatic 'Default' or no categories | ||||
|                     defaultCategoryId == 0 || categories.isEmpty() -> { | ||||
|                     defaultCategoryId == 0L || categories.isEmpty() -> { | ||||
|                         val result = updateManga.awaitUpdateFavorite(manga.id, true) | ||||
|                         if (!result) return@launchIO | ||||
|                         moveMangaToCategory(manga.toDbManga(), null) | ||||
|                         moveMangaToCategory(null) | ||||
|                         launchUI { onAdded() } | ||||
|                     } | ||||
|  | ||||
| @@ -326,7 +324,7 @@ class MangaPresenter( | ||||
|      * @return List of categories, not including the default category | ||||
|      */ | ||||
|     suspend fun getCategories(): List<Category> { | ||||
|         return getCategories.await().map { it.toDbCategory() } | ||||
|         return getCategories.await() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -335,15 +333,15 @@ class MangaPresenter( | ||||
|      * @param manga the manga to get categories from. | ||||
|      * @return Array of category ids the manga is in, if none returns default id | ||||
|      */ | ||||
|     fun getMangaCategoryIds(manga: DomainManga): Array<Int> { | ||||
|     fun getMangaCategoryIds(manga: DomainManga): Array<Long> { | ||||
|         val categories = runBlocking { getCategories.await(manga.id) } | ||||
|         return categories.map { it.id.toInt() }.toTypedArray() | ||||
|         return categories.map { it.id }.toTypedArray() | ||||
|     } | ||||
|  | ||||
|     fun moveMangaToCategoriesAndAddToLibrary(manga: Manga, categories: List<Category>) { | ||||
|         moveMangaToCategories(manga, categories) | ||||
|     fun moveMangaToCategoriesAndAddToLibrary(manga: DomainManga, categories: List<Category>) { | ||||
|         moveMangaToCategories(categories) | ||||
|         presenterScope.launchIO { | ||||
|             updateManga.awaitUpdateFavorite(manga.id!!, true) | ||||
|             updateManga.awaitUpdateFavorite(manga.id, true) | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -353,9 +351,8 @@ class MangaPresenter( | ||||
|      * @param manga the manga to move. | ||||
|      * @param categories the selected categories. | ||||
|      */ | ||||
|     private fun moveMangaToCategories(manga: Manga, categories: List<Category>) { | ||||
|         val mangaId = manga.id ?: return | ||||
|         val categoryIds = categories.mapNotNull { it.id?.toLong() } | ||||
|     private fun moveMangaToCategories(categories: List<Category>) { | ||||
|         val categoryIds = categories.map { it.id } | ||||
|         presenterScope.launchIO { | ||||
|             setMangaCategories.await(mangaId, categoryIds) | ||||
|         } | ||||
| @@ -367,8 +364,8 @@ class MangaPresenter( | ||||
|      * @param manga the manga to move. | ||||
|      * @param category the selected category, or null for default category. | ||||
|      */ | ||||
|     private fun moveMangaToCategory(manga: Manga, category: Category?) { | ||||
|         moveMangaToCategories(manga, listOfNotNull(category)) | ||||
|     private fun moveMangaToCategory(category: Category?) { | ||||
|         moveMangaToCategories(listOfNotNull(category)) | ||||
|     } | ||||
|  | ||||
|     private fun observeTrackingCount() { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user