Edit manga status + edit local manga fixes

This commit is contained in:
Jobobby04 2021-02-24 16:15:19 -05:00
parent f1cb4c38a2
commit 5a67d8169d
13 changed files with 175 additions and 58 deletions

View File

@ -59,8 +59,8 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
COL_DESCRIPTION to obj.originalDescription,
COL_GENRE to obj.originalGenre,
COL_TITLE to obj.originalTitle,
COL_STATUS to obj.originalStatus,
// SY <--
COL_STATUS to obj.status,
COL_THUMBNAIL_URL to obj.thumbnail_url,
COL_FAVORITE to obj.favorite,
COL_LAST_UPDATE to obj.last_update,

View File

@ -40,9 +40,11 @@ open class MangaImpl : Manga {
override var genre: String?
get() = if (favorite) customMangaManager.getManga(this)?.genre ?: ogGenre else ogGenre
set(value) { ogGenre = value }
// SY <--
override var status: Int = 0
override var status: Int
get() = if (favorite) customMangaManager.getManga(this)?.status?.takeUnless { it == 0 } ?: ogStatus else ogStatus
set(value) { ogStatus = value }
// SY <--
override var thumbnail_url: String? = null
@ -71,6 +73,8 @@ open class MangaImpl : Manga {
private set
var ogGenre: String? = null
private set
var ogStatus: Int = 0
private set
// SY <--
override fun equals(other: Any?): Boolean {

View File

@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaInfoPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaMigrationPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaThumbnailPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaTitlePutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaViewerPutResolver
import eu.kanade.tachiyomi.data.database.tables.CategoryTable
@ -102,6 +103,11 @@ interface MangaQueries : DbProvider {
.`object`(manga)
.withPutResolver(MangaMigrationPutResolver())
.prepare()
fun updateMangaThumbnail(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaThumbnailPutResolver())
.prepare()
// SY <--
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.data.database.resolvers
import android.content.ContentValues
import androidx.core.content.contentValuesOf
import com.pushtorefresh.storio.sqlite.StorIOSQLite
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
@ -9,6 +8,7 @@ import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable
import exh.util.nullIfZero
class MangaInfoPutResolver(val reset: Boolean = false) : PutResolver<Manga>() {
@ -31,15 +31,20 @@ class MangaInfoPutResolver(val reset: Boolean = false) : PutResolver<Manga>() {
MangaTable.COL_GENRE to manga.originalGenre,
MangaTable.COL_AUTHOR to manga.originalAuthor,
MangaTable.COL_ARTIST to manga.originalArtist,
MangaTable.COL_DESCRIPTION to manga.originalDescription
MangaTable.COL_DESCRIPTION to manga.originalDescription,
MangaTable.COL_STATUS to manga.originalStatus
)
fun resetToContentValues(manga: Manga) = ContentValues(1).apply {
val splitter = "▒ ▒∩▒"
put(MangaTable.COL_TITLE, manga.title.split(splitter).last())
put(MangaTable.COL_GENRE, manga.genre?.split(splitter)?.lastOrNull())
put(MangaTable.COL_AUTHOR, manga.author?.split(splitter)?.lastOrNull())
put(MangaTable.COL_ARTIST, manga.artist?.split(splitter)?.lastOrNull())
put(MangaTable.COL_DESCRIPTION, manga.description?.split(splitter)?.lastOrNull())
private fun resetToContentValues(manga: Manga) = contentValuesOf(
MangaTable.COL_TITLE to manga.title.split(splitter).last(),
MangaTable.COL_GENRE to manga.genre?.split(splitter)?.lastOrNull(),
MangaTable.COL_AUTHOR to manga.author?.split(splitter)?.lastOrNull(),
MangaTable.COL_ARTIST to manga.artist?.split(splitter)?.lastOrNull(),
MangaTable.COL_DESCRIPTION to manga.description?.split(splitter)?.lastOrNull(),
MangaTable.COL_STATUS to manga.status.nullIfZero()?.toString()?.split(splitter)?.lastOrNull()
)
companion object {
const val splitter = "▒ ▒∩▒"
}
}

View File

@ -0,0 +1,32 @@
package eu.kanade.tachiyomi.data.database.resolvers
import androidx.core.content.contentValuesOf
import com.pushtorefresh.storio.sqlite.StorIOSQLite
import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
import com.pushtorefresh.storio.sqlite.operations.put.PutResult
import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
import eu.kanade.tachiyomi.data.database.inTransactionReturn
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.tables.MangaTable
// SY
class MangaThumbnailPutResolver : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga)
val contentValues = mapToContentValues(manga)
val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
}
fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
.table(MangaTable.TABLE)
.where("${MangaTable.COL_ID} = ?")
.whereArgs(manga.id)
.build()
fun mapToContentValues(manga: Manga) = contentValuesOf(
MangaTable.COL_THUMBNAIL_URL to manga.thumbnail_url
)
}

View File

@ -23,7 +23,7 @@ import uy.kohesive.injekt.injectLazy
*
* @param context the application context.
*/
class DownloadManager(/* SY private */ val context: Context) {
class DownloadManager(private val context: Context) {
private val sourceManager: SourceManager by injectLazy()
private val preferences: PreferencesHelper by injectLazy()

View File

@ -32,30 +32,15 @@ class CustomMangaManager(val context: Context) {
val mangasJson = json.mangas ?: return mutableMapOf()
return mangasJson.mapNotNull { mangaJson ->
val id = mangaJson.id ?: return@mapNotNull null
val manga = MangaImpl().apply {
this.id = id
title = mangaJson.title ?: ""
author = mangaJson.author
artist = mangaJson.artist
description = mangaJson.description
genre = mangaJson.genre?.joinToString(", ")
}
id to manga
id to mangaJson.toManga()
}.toMap().toMutableMap()
}
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!!)
} else {
customMangaMap[manga.id!!] = MangaImpl().apply {
id = manga.id
title = manga.title ?: ""
author = manga.author
artist = manga.artist
description = manga.description
genre = manga.genre?.joinToString(", ")
}
customMangaMap[manga.id!!] = manga.toManga()
}
saveCustomInfo()
}
@ -75,7 +60,8 @@ class CustomMangaManager(val context: Context) {
author,
artist,
description,
genre?.split(", ")
genre?.split(", "),
status
)
}
@ -91,9 +77,20 @@ class CustomMangaManager(val context: Context) {
val author: String? = null,
val artist: String? = null,
val description: String? = null,
val genre: List<String>? = null
val genre: List<String>? = null,
val status: Int? = null
) {
fun toManga() = MangaImpl().apply {
id = this@MangaJson.id
title = this@MangaJson.title ?: ""
author = this@MangaJson.author
artist = this@MangaJson.artist
description = this@MangaJson.description
genre = this@MangaJson.genre?.joinToString(", ")
status = this@MangaJson.status ?: 0
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

View File

@ -64,6 +64,12 @@ class LocalSource(private val context: Context) : CatalogueSource {
val c = context.getString(R.string.app_name) + File.separator + "local"
return DiskUtil.getExternalStorages(context).map { File(it.absolutePath, c) }
}
// SY -->
val json = Json {
prettyPrint = true
}
// SY <--
}
override val id = ID
@ -151,19 +157,16 @@ class LocalSource(private val context: Context) : CatalogueSource {
// SY -->
fun updateMangaInfo(manga: SManga) {
val directory = getBaseDirectories(context).mapNotNull { File(it, manga.url) }.find {
val directory = getBaseDirectories(context).map { File(it, manga.url) }.find {
it.exists()
} ?: return
val json = Json {
prettyPrint = true
}
val existingFileName = directory.listFiles()?.find { it.extension == "json" }?.name
val file = File(directory, existingFileName ?: "info.json")
file.writeText(json.encodeToString(manga.toJson()))
}
private fun SManga.toJson(): MangaJson {
return MangaJson(title, author, artist, description, genre?.split(", ")?.toTypedArray())
return MangaJson(title, author, artist, description, genre?.split(", "), status)
}
@Serializable
@ -172,7 +175,8 @@ class LocalSource(private val context: Context) : CatalogueSource {
val author: String?,
val artist: String?,
val description: String?,
val genre: Array<String>?
val genre: List<String>?,
val status: Int
) {
override fun equals(other: Any?): Boolean {

View File

@ -35,6 +35,8 @@ interface SManga : Serializable {
get() = (this as? MangaImpl)?.ogDesc ?: description
val originalGenre: String?
get() = (this as? MangaImpl)?.ogGenre ?: genre
val originalStatus: Int
get() = (this as? MangaImpl)?.ogStatus ?: status
// SY <--
fun copyFrom(other: SManga) {

View File

@ -5,6 +5,7 @@ import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.text.InputType
import android.widget.ArrayAdapter
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.core.view.children
@ -23,10 +24,12 @@ import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.databinding.EditMangaDialogBinding
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.util.lang.chop
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.toast
import exh.util.dropBlank
import exh.util.trimOrNull
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
@ -84,6 +87,36 @@ class EditMangaDialog : DialogController {
val isLocal = manga.source == LocalSource.ID
val statusAdapter: ArrayAdapter<String> = ArrayAdapter(
context,
android.R.layout.simple_spinner_item,
listOf(
R.string.manga,
R.string.ongoing,
R.string.completed,
R.string.licensed,
R.string.publication_complete,
R.string.hiatus,
R.string.cancelled
).map { context.getString(it) }
)
binding.status.adapter = statusAdapter
if (manga.status != manga.originalStatus) {
binding.status.setSelection(
when (manga.status) {
SManga.UNKNOWN -> 0
SManga.ONGOING -> 1
SManga.COMPLETED -> 2
SManga.LICENSED -> 3
SManga.PUBLICATION_COMPLETE -> 4
SManga.HIATUS -> 5
SManga.CANCELLED -> 6
else -> 0
}
)
}
if (isLocal) {
if (manga.title != manga.url) {
binding.title.setText(manga.title)
@ -92,7 +125,7 @@ class EditMangaDialog : DialogController {
binding.mangaAuthor.setText(manga.author.orEmpty())
binding.mangaArtist.setText(manga.artist.orEmpty())
binding.mangaDescription.setText(manga.description.orEmpty())
binding.mangaGenresTags.setChips(manga.getGenres().orEmpty())
binding.mangaGenresTags.setChips(manga.getGenres().orEmpty().dropBlank())
} else {
if (manga.title != manga.originalTitle) {
binding.title.append(manga.title)
@ -160,11 +193,23 @@ class EditMangaDialog : DialogController {
private fun onPositiveButtonClick() {
infoController.presenter.updateMangaInfo(
context,
binding.title.text.toString(),
binding.mangaAuthor.text.toString(),
binding.mangaArtist.text.toString(),
binding.mangaDescription.text.toString(),
binding.mangaGenresTags.getTextStrings(),
binding.status.selectedItemPosition.let {
when (it) {
1 -> SManga.ONGOING
2 -> SManga.COMPLETED
3 -> SManga.LICENSED
4 -> SManga.PUBLICATION_COMPLETE
5 -> SManga.HIATUS
6 -> SManga.CANCELLED
else -> null
}
},
customCoverUri,
willResetCover
)

View File

@ -706,7 +706,7 @@ class MangaController :
// SY -->
fun changeCover() {
if (manga?.favorite == true) {
if (manga?.favorite == true || source?.id == LocalSource.ID) {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(
@ -1036,7 +1036,7 @@ class MangaController :
val uri = data.data ?: return
if (editMangaDialog != null) editMangaDialog?.updateCover(uri)
else {
presenter.editCoverWithStream(uri)
presenter.editCoverWithStream(activity, uri)
}
} catch (error: IOException) {
activity.toast(R.string.notification_cover_update_failed)

View File

@ -314,11 +314,13 @@ class MangaPresenter(
// SY -->
fun updateMangaInfo(
context: Context,
title: String?,
author: String?,
artist: String?,
description: String?,
tags: List<String>?,
status: Int?,
uri: Uri?,
resetCover: Boolean = false
) {
@ -329,7 +331,8 @@ class MangaPresenter(
manga.description = description?.trimOrNull()
val tagsString = tags?.joinToString()
manga.genre = if (tags.isNullOrEmpty()) null else tagsString?.trim()
LocalSource(downloadManager.context).updateMangaInfo(manga)
manga.status = status ?: 0
(sourceManager.get(LocalSource.ID) as LocalSource).updateMangaInfo(manga)
db.updateMangaInfo(manga).executeAsBlocking()
} else {
val genre = if (!tags.isNullOrEmpty() && tags.joinToString() != manga.originalGenre) {
@ -343,13 +346,14 @@ class MangaPresenter(
author?.trimOrNull(),
artist?.trimOrNull(),
description?.trimOrNull(),
genre
genre,
status.takeUnless { it == manga.originalStatus }
)
customMangaManager.saveMangaInfo(manga)
}
if (uri != null) {
editCoverWithStream(uri)
editCoverWithStream(context, uri)
} else if (resetCover) {
coverCache.deleteCustomCover(manga)
manga.updateCoverLastModified(db)
@ -377,11 +381,14 @@ class MangaPresenter(
}
}
fun editCoverWithStream(uri: Uri): Boolean {
val inputStream = downloadManager.context.contentResolver.openInputStream(uri) ?: return false
fun editCoverWithStream(context: Context, uri: Uri): Boolean {
val inputStream = context.contentResolver.openInputStream(uri) ?: return false
if (manga.source == LocalSource.ID) {
LocalSource.updateCover(downloadManager.context, manga, inputStream)
manga.updateCoverLastModified(db)
val cover = LocalSource.updateCover(context, manga, inputStream)
if (manga.thumbnail_url.isNullOrBlank() && cover != null) {
manga.thumbnail_url = cover.absolutePath
db.updateMangaThumbnail(manga).executeAsBlocking()
}
return true
}

View File

@ -22,16 +22,31 @@
android:src="@mipmap/ic_launcher"/>
</FrameLayout>
<Button
android:id="@+id/reset_cover"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Theme.Widget.Button.FilledAccent"
android:textAllCaps="false"
android:layout_gravity="center"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="@string/reset_cover" />
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/reset_cover"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Theme.Widget.Button.FilledAccent"
android:textAllCaps="false"
android:layout_gravity="center"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="@string/reset_cover" />
<Spinner
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Theme.Widget.TextInputLayout.OutlinedBox.Dense"