Edit Manga Status (for Local and online

Mostly the same, except custom status can be null so it's not automatically added to the edits.json

Since SY implemented first I'm using the same key for backups, I would've liked if customStatus was nullable but it is what it is

Closes #704

Co-Authored-By: jobobby04 <17078382+jobobby04@users.noreply.github.com>
This commit is contained in:
Jays2Kings 2021-04-14 16:18:58 -04:00
parent 928fc06e58
commit 9e3aaab95f
12 changed files with 61 additions and 18 deletions

View File

@ -66,7 +66,7 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa
val categories = backupManga.categories val categories = backupManga.categories
val history = backupManga.history val history = backupManga.history
val tracks = backupManga.getTrackingImpl() val tracks = backupManga.getTrackingImpl()
val customManga = backupManga.getCustomMangaInfo() val customManga = backupManga.getCustomMangaInfo(manga)
try { try {
restoreMangaData(manga, chapters, categories, history, tracks, backupCategories, customManga) restoreMangaData(manga, chapters, categories, history, tracks, backupCategories, customManga)

View File

@ -36,6 +36,9 @@ data class BackupManga(
@ProtoNumber(101) var chapterFlags: Int = 0, @ProtoNumber(101) var chapterFlags: Int = 0,
@ProtoNumber(102) var history: List<BackupHistory> = emptyList(), @ProtoNumber(102) var history: List<BackupHistory> = emptyList(),
// SY specific values
@ProtoNumber(602) var customStatus: Int = 0,
// J2K specific values // J2K specific values
@ProtoNumber(800) var customTitle: String? = null, @ProtoNumber(800) var customTitle: String? = null,
@ProtoNumber(801) var customArtist: String? = null, @ProtoNumber(801) var customArtist: String? = null,
@ -67,12 +70,13 @@ data class BackupManga(
} }
} }
fun getCustomMangaInfo(): CustomMangaManager.MangaJson? { fun getCustomMangaInfo(manga: Manga): CustomMangaManager.MangaJson? {
if (customTitle != null || if (customTitle != null ||
customArtist != null || customArtist != null ||
customAuthor != null || customAuthor != null ||
customDescription != null || customDescription != null ||
customGenre != null customGenre != null ||
manga.status != customStatus
) { ) {
return CustomMangaManager.MangaJson( return CustomMangaManager.MangaJson(
id = 0L, id = 0L,
@ -80,7 +84,8 @@ data class BackupManga(
author = customAuthor, author = customAuthor,
artist = customArtist, artist = customArtist,
description = customDescription, description = customDescription,
genre = customGenre?.toTypedArray() genre = customGenre?.toTypedArray(),
status = if (manga.status != customStatus) customStatus else null
) )
} }
return null return null
@ -101,7 +106,7 @@ data class BackupManga(
author = manga.originalAuthor, author = manga.originalAuthor,
description = manga.originalDescription, description = manga.originalDescription,
genre = manga.getOriginalGenres() ?: emptyList(), genre = manga.getOriginalGenres() ?: emptyList(),
status = manga.status, status = manga.originalStatus,
thumbnailUrl = manga.thumbnail_url, thumbnailUrl = manga.thumbnail_url,
favorite = manga.favorite, favorite = manga.favorite,
source = manga.source, source = manga.source,
@ -115,6 +120,7 @@ data class BackupManga(
backupManga.customAuthor = it.author backupManga.customAuthor = it.author
backupManga.customDescription = it.description backupManga.customDescription = it.description
backupManga.customGenre = it.getGenres() backupManga.customGenre = it.getGenres()
backupManga.customStatus = it.status
} }
} }
} }

View File

@ -57,7 +57,7 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
put(COL_DESCRIPTION, obj.originalDescription) put(COL_DESCRIPTION, obj.originalDescription)
put(COL_GENRE, obj.originalGenre) put(COL_GENRE, obj.originalGenre)
put(COL_TITLE, obj.originalTitle) put(COL_TITLE, obj.originalTitle)
put(COL_STATUS, obj.status) put(COL_STATUS, obj.originalStatus)
put(COL_THUMBNAIL_URL, obj.thumbnail_url) put(COL_THUMBNAIL_URL, obj.thumbnail_url)
put(COL_FAVORITE, obj.favorite) put(COL_FAVORITE, obj.favorite)
put(COL_LAST_UPDATE, obj.last_update) put(COL_LAST_UPDATE, obj.last_update)

View File

@ -43,7 +43,9 @@ open class MangaImpl : Manga {
get() = if (favorite) customMangaManager.getManga(this)?.genre ?: ogGenre else ogGenre get() = if (favorite) customMangaManager.getManga(this)?.genre ?: ogGenre else ogGenre
set(value) { ogGenre = value } set(value) { ogGenre = value }
override var status: Int = 0 override var status: Int
get() = if (favorite) customMangaManager.getManga(this)?.status ?: ogStatus else ogStatus
set(value) { ogStatus = value }
override var thumbnail_url: String? = null override var thumbnail_url: String? = null
@ -71,6 +73,8 @@ open class MangaImpl : Manga {
private set private set
var ogGenre: String? = null var ogGenre: String? = null
private set private set
var ogStatus: Int = 0
private set
override fun copyFrom(other: SManga) { override fun copyFrom(other: SManga) {
if (other is MangaImpl && other::ogTitle.isInitialized && if (other is MangaImpl && other::ogTitle.isInitialized &&

View File

@ -31,5 +31,6 @@ class MangaInfoPutResolver() : PutResolver<Manga>() {
put(MangaTable.COL_AUTHOR, manga.originalAuthor) put(MangaTable.COL_AUTHOR, manga.originalAuthor)
put(MangaTable.COL_ARTIST, manga.originalArtist) put(MangaTable.COL_ARTIST, manga.originalArtist)
put(MangaTable.COL_DESCRIPTION, manga.originalDescription) put(MangaTable.COL_DESCRIPTION, manga.originalDescription)
put(MangaTable.COL_STATUS, manga.originalStatus)
} }
} }

View File

@ -1,6 +1,7 @@
package eu.kanade.tachiyomi.data.library package eu.kanade.tachiyomi.data.library
import android.content.Context import android.content.Context
import com.github.salomonbrys.kotson.nullInt
import com.github.salomonbrys.kotson.nullLong import com.github.salomonbrys.kotson.nullLong
import com.github.salomonbrys.kotson.nullString import com.github.salomonbrys.kotson.nullString
import com.github.salomonbrys.kotson.set import com.github.salomonbrys.kotson.set
@ -48,13 +49,14 @@ class CustomMangaManager(val context: Context) {
description = mangaObject["description"]?.nullString description = mangaObject["description"]?.nullString
genre = mangaObject["genre"]?.asJsonArray?.mapNotNull { it.nullString } genre = mangaObject["genre"]?.asJsonArray?.mapNotNull { it.nullString }
?.joinToString(", ") ?.joinToString(", ")
status = mangaObject["status"]?.nullInt ?: 0
} }
id to manga id to manga
}.toMap().toMutableMap() }.toMap().toMutableMap()
} }
fun saveMangaInfo(manga: MangaJson) { fun saveMangaInfo(manga: MangaJson) {
if (manga.title == null && manga.author == null && manga.artist == null && manga.description == null && manga.genre == null) { if (manga.title == null && manga.author == null && manga.artist == null && manga.description == null && manga.genre == null && manga.status == null) {
customMangaMap.remove(manga.id) customMangaMap.remove(manga.id)
} else { } else {
customMangaMap[manga.id] = MangaImpl().apply { customMangaMap[manga.id] = MangaImpl().apply {
@ -64,6 +66,7 @@ class CustomMangaManager(val context: Context) {
artist = manga.artist artist = manga.artist
description = manga.description description = manga.description
genre = manga.genre?.joinToString(", ") genre = manga.genre?.joinToString(", ")
status = manga.status ?: -1
} }
} }
saveCustomInfo() saveCustomInfo()
@ -89,7 +92,8 @@ class CustomMangaManager(val context: Context) {
author, author,
artist, artist,
description, description,
genre?.split(", ")?.toTypedArray() genre?.split(", ")?.toTypedArray(),
status.takeUnless { it == -1 }
) )
} }
@ -99,7 +103,8 @@ class CustomMangaManager(val context: Context) {
val author: String? = null, val author: String? = null,
val artist: String? = null, val artist: String? = null,
val description: String? = null, val description: String? = null,
val genre: Array<String>? = null val genre: Array<String>? = null,
val status: Int? = null
) { ) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {

View File

@ -200,7 +200,7 @@ class LocalSource(private val context: Context) : CatalogueSource {
} }
fun SManga.toJson(): MangaJson { fun SManga.toJson(): MangaJson {
return MangaJson(title, author, artist, description, genre?.split(", ")?.toTypedArray()) return MangaJson(title, author, artist, description, genre?.split(", ")?.toTypedArray(), status)
} }
data class MangaJson( data class MangaJson(
@ -208,7 +208,8 @@ class LocalSource(private val context: Context) : CatalogueSource {
val author: String?, val author: String?,
val artist: String?, val artist: String?,
val description: String?, val description: String?,
val genre: Array<String>? val genre: Array<String>?,
val status: Int?,
) { ) {
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {

View File

@ -34,6 +34,8 @@ interface SManga : Serializable {
get() = (this as? MangaImpl)?.ogDesc ?: description get() = (this as? MangaImpl)?.ogDesc ?: description
val originalGenre: String? val originalGenre: String?
get() = (this as? MangaImpl)?.ogGenre ?: genre get() = (this as? MangaImpl)?.ogGenre ?: genre
val originalStatus: Int
get() = (this as? MangaImpl)?.ogStatus ?: status
fun copyFrom(other: SManga) { fun copyFrom(other: SManga) {
if (other.author != null) { if (other.author != null) {
@ -56,7 +58,7 @@ interface SManga : Serializable {
thumbnail_url = other.thumbnail_url thumbnail_url = other.thumbnail_url
} }
status = other.status status = other.originalStatus
if (!initialized) { if (!initialized) {
initialized = other.initialized initialized = other.initialized

View File

@ -14,7 +14,9 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.image.coil.MangaFetcher import eu.kanade.tachiyomi.data.image.coil.MangaFetcher
import eu.kanade.tachiyomi.databinding.EditMangaDialogBinding import eu.kanade.tachiyomi.databinding.EditMangaDialogBinding
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.util.isLocal
import eu.kanade.tachiyomi.util.lang.chop import eu.kanade.tachiyomi.util.lang.chop
import eu.kanade.tachiyomi.util.view.visibleIf import eu.kanade.tachiyomi.util.view.visibleIf
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -66,7 +68,7 @@ class EditMangaDialog : DialogController {
fun onViewCreated() { fun onViewCreated() {
binding.mangaCover.loadAny(manga) binding.mangaCover.loadAny(manga)
val isLocal = manga.source == LocalSource.ID val isLocal = manga.isLocal()
if (isLocal) { if (isLocal) {
if (manga.title != manga.url) { if (manga.title != manga.url) {
@ -107,13 +109,14 @@ class EditMangaDialog : DialogController {
)?.chop(20)}" )?.chop(20)}"
} }
} }
binding.mangaStatus.setSelection(manga.status.coerceIn(SManga.UNKNOWN, SManga.LICENSED))
binding.mangaGenresTags.clearFocus() binding.mangaGenresTags.clearFocus()
binding.coverLayout.setOnClickListener { binding.coverLayout.setOnClickListener {
infoController.changeCover() infoController.changeCover()
} }
binding.resetTags.setOnClickListener { resetTags() } binding.resetTags.setOnClickListener { resetTags() }
binding.resetTags.text = resources?.getString( binding.resetTags.text = resources?.getString(
if (manga.genre.isNullOrBlank() || manga.source == LocalSource.ID) { if (manga.originalGenre.isNullOrBlank() || isLocal) {
R.string.clear_tags R.string.clear_tags
} else { } else {
R.string.reset_tags R.string.reset_tags
@ -152,6 +155,7 @@ class EditMangaDialog : DialogController {
customCoverUri, customCoverUri,
binding.mangaDescription.text.toString(), binding.mangaDescription.text.toString(),
binding.mangaGenresTags.tags, binding.mangaGenresTags.tags,
binding.mangaStatus.selectedPosition,
willResetCover willResetCover
) )
} }

View File

@ -30,6 +30,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.model.toSChapter import eu.kanade.tachiyomi.source.model.toSChapter
import eu.kanade.tachiyomi.source.model.toSManga import eu.kanade.tachiyomi.source.model.toSManga
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
@ -573,7 +574,6 @@ class MangaDetailsPresenter(
fun confirmDeletion() { fun confirmDeletion() {
coverCache.deleteFromCache(manga) coverCache.deleteFromCache(manga)
db.resetMangaInfo(manga).executeAsBlocking()
downloadManager.deleteManga(manga, source) downloadManager.deleteManga(manga, source)
customMangaManager.saveMangaInfo(CustomMangaManager.MangaJson(manga.id!!)) customMangaManager.saveMangaInfo(CustomMangaManager.MangaJson(manga.id!!))
asyncUpdateMangaAndChapters(true) asyncUpdateMangaAndChapters(true)
@ -629,6 +629,7 @@ class MangaDetailsPresenter(
uri: Uri?, uri: Uri?,
description: String?, description: String?,
tags: Array<String>?, tags: Array<String>?,
status: Int?,
resetCover: Boolean = false resetCover: Boolean = false
) { ) {
if (manga.source == LocalSource.ID) { if (manga.source == LocalSource.ID) {
@ -638,6 +639,7 @@ class MangaDetailsPresenter(
manga.description = description?.trimOrNull() manga.description = description?.trimOrNull()
val tagsString = tags?.joinToString(", ") { it.capitalize() } val tagsString = tags?.joinToString(", ") { it.capitalize() }
manga.genre = if (tags.isNullOrEmpty()) null else tagsString?.trim() manga.genre = if (tags.isNullOrEmpty()) null else tagsString?.trim()
manga.status = status ?: SManga.UNKNOWN
LocalSource(downloadManager.context).updateMangaInfo(manga) LocalSource(downloadManager.context).updateMangaInfo(manga)
db.updateMangaInfo(manga).executeAsBlocking() db.updateMangaInfo(manga).executeAsBlocking()
} else { } else {
@ -652,7 +654,8 @@ class MangaDetailsPresenter(
author?.trimOrNull(), author?.trimOrNull(),
artist?.trimOrNull(), artist?.trimOrNull(),
description?.trimOrNull(), description?.trimOrNull(),
genre genre,
if (status != this.manga.originalStatus) status else null
) )
customMangaManager.saveMangaInfo(manga) customMangaManager.saveMangaInfo(manga)
} }

View File

@ -35,6 +35,16 @@
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:text="@string/reset_cover" /> android:text="@string/reset_cover" />
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
android:id="@+id/manga_status"
app:title="@string/status"
android:layout_marginEnd="32dp"
android:layout_marginStart="32dp"
android:layout_marginBottom="6dp"
android:entries="@array/manga_statuses"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText <EditText
android:id="@+id/title" android:id="@+id/title"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -97,7 +107,7 @@
android:id="@+id/reset_tags" android:id="@+id/reset_tags"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.Button.OutlinedButton" style="@style/Theme.Widget.Button.Primary"
android:textAllCaps="false" android:textAllCaps="false"
android:layout_marginEnd="16dp" android:layout_marginEnd="16dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"

View File

@ -26,6 +26,13 @@
<item>@string/smart_fit</item> <item>@string/smart_fit</item>
</string-array> </string-array>
<string-array name="manga_statuses">
<item>@string/unknown_status</item>
<item>@string/ongoing</item>
<item>@string/completed</item>
<item>@string/licensed</item>
</string-array>
<string-array name="webtoon_side_padding"> <string-array name="webtoon_side_padding">
<item>@string/webtoon_side_padding_0</item> <item>@string/webtoon_side_padding_0</item>
<item>@string/webtoon_side_padding_10</item> <item>@string/webtoon_side_padding_10</item>