Very basic manga info edit, currently will break everything if used, tags and cover edit not working
This commit is contained in:
parent
bbf1c4ffd9
commit
044c638079
@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.data.cache.ChapterCache
|
|||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
|
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||||
@ -42,6 +43,8 @@ class AppModule(val app: Application) : InjektModule {
|
|||||||
|
|
||||||
addSingletonFactory { DownloadManager(app) }
|
addSingletonFactory { DownloadManager(app) }
|
||||||
|
|
||||||
|
addSingletonFactory { CustomMangaManager(app) }
|
||||||
|
|
||||||
addSingletonFactory { TrackManager(app) }
|
addSingletonFactory { TrackManager(app) }
|
||||||
|
|
||||||
addSingletonFactory { Gson() }
|
addSingletonFactory { Gson() }
|
||||||
@ -63,5 +66,7 @@ class AppModule(val app: Application) : InjektModule {
|
|||||||
GlobalScope.launch { get<DatabaseHelper>() }
|
GlobalScope.launch { get<DatabaseHelper>() }
|
||||||
|
|
||||||
GlobalScope.launch { get<DownloadManager>() }
|
GlobalScope.launch { get<DownloadManager>() }
|
||||||
|
|
||||||
|
GlobalScope.launch { get<CustomMangaManager>() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.data.database.models
|
package eu.kanade.tachiyomi.data.database.models
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
open class MangaImpl : Manga {
|
open class MangaImpl : Manga {
|
||||||
|
|
||||||
override var id: Long? = null
|
override var id: Long? = null
|
||||||
@ -8,17 +11,34 @@ open class MangaImpl : Manga {
|
|||||||
|
|
||||||
override lateinit var url: String
|
override lateinit var url: String
|
||||||
|
|
||||||
// SY -->
|
private val customMangaManager: CustomMangaManager by injectLazy()
|
||||||
override var title: String = ""
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
override var artist: String? = null
|
override var title: String
|
||||||
|
get() = if (favorite) {
|
||||||
|
val customTitle = customMangaManager.getManga(this)?.title
|
||||||
|
if (customTitle.isNullOrBlank()) ogTitle else customTitle
|
||||||
|
} else {
|
||||||
|
ogTitle
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
ogTitle = value
|
||||||
|
}
|
||||||
|
|
||||||
override var author: String? = null
|
override var author: String?
|
||||||
|
get() = if (favorite) customMangaManager.getManga(this)?.author ?: ogAuthor else ogAuthor
|
||||||
|
set(value) { ogAuthor = value }
|
||||||
|
|
||||||
override var description: String? = null
|
override var artist: String?
|
||||||
|
get() = if (favorite) customMangaManager.getManga(this)?.artist ?: ogArtist else ogArtist
|
||||||
|
set(value) { ogArtist = value }
|
||||||
|
|
||||||
override var genre: String? = null
|
override var description: String?
|
||||||
|
get() = if (favorite) customMangaManager.getManga(this)?.description ?: ogDesc else ogDesc
|
||||||
|
set(value) { ogDesc = value }
|
||||||
|
|
||||||
|
override var genre: String?
|
||||||
|
get() = if (favorite) customMangaManager.getManga(this)?.genre ?: ogGenre else ogGenre
|
||||||
|
set(value) { ogGenre = value }
|
||||||
|
|
||||||
override var status: Int = 0
|
override var status: Int = 0
|
||||||
|
|
||||||
@ -36,6 +56,17 @@ open class MangaImpl : Manga {
|
|||||||
|
|
||||||
override var cover_last_modified: Long = 0
|
override var cover_last_modified: Long = 0
|
||||||
|
|
||||||
|
lateinit var ogTitle: String
|
||||||
|
private set
|
||||||
|
var ogAuthor: String? = null
|
||||||
|
private set
|
||||||
|
var ogArtist: String? = null
|
||||||
|
private set
|
||||||
|
var ogDesc: String? = null
|
||||||
|
private set
|
||||||
|
var ogGenre: String? = null
|
||||||
|
private set
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (other == null || javaClass != other.javaClass) return false
|
if (other == null || javaClass != other.javaClass) return false
|
||||||
|
@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
|
|||||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaCoverLastModifiedPutResolver
|
import eu.kanade.tachiyomi.data.database.resolvers.MangaCoverLastModifiedPutResolver
|
||||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
|
import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
|
||||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
|
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.MangaLastUpdatedPutResolver
|
||||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaTitlePutResolver
|
import eu.kanade.tachiyomi.data.database.resolvers.MangaTitlePutResolver
|
||||||
import eu.kanade.tachiyomi.data.database.resolvers.MangaViewerPutResolver
|
import eu.kanade.tachiyomi.data.database.resolvers.MangaViewerPutResolver
|
||||||
@ -84,6 +85,16 @@ interface MangaQueries : DbProvider {
|
|||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.prepare()
|
.prepare()
|
||||||
|
|
||||||
|
fun updateMangaInfo(manga: Manga) = db.put()
|
||||||
|
.`object`(manga)
|
||||||
|
.withPutResolver(MangaInfoPutResolver())
|
||||||
|
.prepare()
|
||||||
|
|
||||||
|
fun resetMangaInfo(manga: Manga) = db.put()
|
||||||
|
.`object`(manga)
|
||||||
|
.withPutResolver(MangaInfoPutResolver(true))
|
||||||
|
.prepare()
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
|
fun insertManga(manga: Manga) = db.put().`object`(manga).prepare()
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.database.resolvers
|
||||||
|
|
||||||
|
import android.content.ContentValues
|
||||||
|
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
|
||||||
|
|
||||||
|
class MangaInfoPutResolver(val reset: Boolean = false) : PutResolver<Manga>() {
|
||||||
|
|
||||||
|
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
|
||||||
|
val updateQuery = mapToUpdateQuery(manga)
|
||||||
|
val contentValues = if (reset) resetToContentValues(manga) else 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) = ContentValues(1).apply {
|
||||||
|
put(MangaTable.COL_TITLE, manga.originalTitle)
|
||||||
|
put(MangaTable.COL_GENRE, manga.originalGenre)
|
||||||
|
put(MangaTable.COL_AUTHOR, manga.originalAuthor)
|
||||||
|
put(MangaTable.COL_ARTIST, manga.originalArtist)
|
||||||
|
put(MangaTable.COL_DESCRIPTION, manga.originalDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,7 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
*
|
*
|
||||||
* @param context the application context.
|
* @param context the application context.
|
||||||
*/
|
*/
|
||||||
class DownloadManager(private val context: Context) {
|
class DownloadManager(val context: Context) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The sources manager.
|
* The sources manager.
|
||||||
|
@ -0,0 +1,111 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.library
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.github.salomonbrys.kotson.nullLong
|
||||||
|
import com.github.salomonbrys.kotson.nullString
|
||||||
|
import com.github.salomonbrys.kotson.set
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
|
import java.io.File
|
||||||
|
import java.util.Scanner
|
||||||
|
|
||||||
|
class CustomMangaManager(val context: Context) {
|
||||||
|
|
||||||
|
private val editJson = File(context.getExternalFilesDir(null), "edits.json")
|
||||||
|
|
||||||
|
private var customMangaMap = mutableMapOf<Long, Manga>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
fetchCustomData()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getManga(manga: Manga): Manga? = customMangaMap[manga.id]
|
||||||
|
|
||||||
|
private fun fetchCustomData() {
|
||||||
|
if (!editJson.exists() || !editJson.isFile) return
|
||||||
|
|
||||||
|
val json = try {
|
||||||
|
Gson().fromJson(
|
||||||
|
Scanner(editJson).useDelimiter("\\Z").next(), JsonObject::class.java
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
} ?: return
|
||||||
|
|
||||||
|
val mangasJson = json.get("mangas").asJsonArray ?: return
|
||||||
|
customMangaMap = mangasJson.mapNotNull { element ->
|
||||||
|
val mangaObject = element.asJsonObject ?: return@mapNotNull null
|
||||||
|
val id = mangaObject["id"]?.nullLong ?: return@mapNotNull null
|
||||||
|
val manga = MangaImpl().apply {
|
||||||
|
this.id = id
|
||||||
|
title = mangaObject["title"]?.nullString ?: ""
|
||||||
|
author = mangaObject["author"]?.nullString
|
||||||
|
artist = mangaObject["artist"]?.nullString
|
||||||
|
description = mangaObject["description"]?.nullString
|
||||||
|
genre = mangaObject["genre"]?.asJsonArray?.mapNotNull { it.nullString }
|
||||||
|
?.joinToString(", ")
|
||||||
|
}
|
||||||
|
id to manga
|
||||||
|
}.toMap().toMutableMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveMangaInfo(manga: MangaJson) {
|
||||||
|
if (manga.title == null && manga.author == null && manga.artist == null && manga.description == null && manga.genre == 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(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
saveCustomInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun saveCustomInfo() {
|
||||||
|
val jsonElements = customMangaMap.values.map { it.toJson() }
|
||||||
|
if (jsonElements.isNotEmpty()) {
|
||||||
|
val gson = GsonBuilder().create()
|
||||||
|
val root = JsonObject()
|
||||||
|
val mangaEntries = gson.toJsonTree(jsonElements)
|
||||||
|
|
||||||
|
root["mangas"] = mangaEntries
|
||||||
|
editJson.delete()
|
||||||
|
editJson.writeText(gson.toJson(root))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Manga.toJson(): MangaJson {
|
||||||
|
return MangaJson(
|
||||||
|
id!!, title, author, artist, description, genre?.split(", ")?.toTypedArray()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MangaJson(
|
||||||
|
val id: Long,
|
||||||
|
val title: String? = null,
|
||||||
|
val author: String? = null,
|
||||||
|
val artist: String? = null,
|
||||||
|
val description: String? = null,
|
||||||
|
val genre: Array<String>? = null
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as MangaJson
|
||||||
|
if (id != other.id) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return id.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.source
|
package eu.kanade.tachiyomi.source
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
@ -135,6 +136,44 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
return Observable.just(MangasPage(mangas, false))
|
return Observable.just(MangasPage(mangas, false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateMangaInfo(manga: SManga) {
|
||||||
|
val directory = getBaseDirectories(context).mapNotNull { File(it, manga.url) }.find {
|
||||||
|
it.exists()
|
||||||
|
} ?: return
|
||||||
|
val gson = GsonBuilder().setPrettyPrinting().create()
|
||||||
|
val existingFileName = directory.listFiles()?.find { it.extension == "json" }?.name
|
||||||
|
val file = File(directory, existingFileName ?: "info.json")
|
||||||
|
file.writeText(gson.toJson(manga.toJson()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SManga.toJson(): MangaJson {
|
||||||
|
return MangaJson(title, author, artist, description, genre?.split(", ")?.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MangaJson(
|
||||||
|
val title: String,
|
||||||
|
val author: String?,
|
||||||
|
val artist: String?,
|
||||||
|
val description: String?,
|
||||||
|
val genre: Array<String>?
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as MangaJson
|
||||||
|
|
||||||
|
if (title != other.title) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return title.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS)
|
override fun fetchLatestUpdates(page: Int) = fetchSearchManga(page, "", LATEST_FILTERS)
|
||||||
|
|
||||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.source.model
|
package eu.kanade.tachiyomi.source.model
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
interface SManga : Serializable {
|
interface SManga : Serializable {
|
||||||
@ -22,27 +23,38 @@ interface SManga : Serializable {
|
|||||||
|
|
||||||
var initialized: Boolean
|
var initialized: Boolean
|
||||||
|
|
||||||
|
val originalTitle: String
|
||||||
|
get() = (this as? MangaImpl)?.ogTitle ?: title
|
||||||
|
val originalAuthor: String?
|
||||||
|
get() = (this as? MangaImpl)?.ogAuthor ?: author
|
||||||
|
val originalArtist: String?
|
||||||
|
get() = (this as? MangaImpl)?.ogArtist ?: artist
|
||||||
|
val originalDescription: String?
|
||||||
|
get() = (this as? MangaImpl)?.ogDesc ?: description
|
||||||
|
val originalGenre: String?
|
||||||
|
get() = (this as? MangaImpl)?.ogGenre ?: genre
|
||||||
|
|
||||||
fun copyFrom(other: SManga) {
|
fun copyFrom(other: SManga) {
|
||||||
// EXH -->
|
// EXH -->
|
||||||
if (other.title.isNotBlank()) {
|
if (other.title.isNotBlank()) {
|
||||||
title = other.title
|
title = other.originalTitle
|
||||||
}
|
}
|
||||||
// EXH <--
|
// EXH <--
|
||||||
|
|
||||||
if (other.author != null) {
|
if (other.author != null) {
|
||||||
author = other.author
|
author = other.originalAuthor
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other.artist != null) {
|
if (other.artist != null) {
|
||||||
artist = other.artist
|
artist = other.originalArtist
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other.description != null) {
|
if (other.description != null) {
|
||||||
description = other.description
|
description = other.originalDescription
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other.genre != null) {
|
if (other.genre != null) {
|
||||||
genre = other.genre
|
genre = other.originalGenre
|
||||||
}
|
}
|
||||||
|
|
||||||
if (other.thumbnail_url != null) {
|
if (other.thumbnail_url != null) {
|
||||||
@ -61,9 +73,6 @@ interface SManga : Serializable {
|
|||||||
const val ONGOING = 1
|
const val ONGOING = 1
|
||||||
const val COMPLETED = 2
|
const val COMPLETED = 2
|
||||||
const val LICENSED = 3
|
const val LICENSED = 3
|
||||||
// SY -->
|
|
||||||
const val RECOMMENDS = 69 // nice
|
|
||||||
// SY <--
|
|
||||||
|
|
||||||
fun create(): SManga {
|
fun create(): SManga {
|
||||||
return SMangaImpl()
|
return SMangaImpl()
|
||||||
|
@ -0,0 +1,179 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
|
import com.afollestad.materialdialogs.customview.customView
|
||||||
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
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.glide.GlideApp
|
||||||
|
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
||||||
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
|
import eu.kanade.tachiyomi.util.lang.chop
|
||||||
|
import eu.kanade.tachiyomi.util.view.setChips
|
||||||
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_artist
|
||||||
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_author
|
||||||
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_cover
|
||||||
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_description
|
||||||
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_genres_tags
|
||||||
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.reset_tags
|
||||||
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.title
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
|
class EditMangaDialog : DialogController {
|
||||||
|
|
||||||
|
private var dialogView: View? = null
|
||||||
|
|
||||||
|
private val manga: Manga
|
||||||
|
|
||||||
|
// private var customCoverUri: Uri? = null
|
||||||
|
|
||||||
|
private var willResetCover = false
|
||||||
|
|
||||||
|
private val infoController
|
||||||
|
get() = targetController as MangaAllInOneController
|
||||||
|
|
||||||
|
constructor(target: MangaAllInOneController, manga: Manga) : super(
|
||||||
|
Bundle()
|
||||||
|
.apply {
|
||||||
|
putLong(KEY_MANGA, manga.id!!)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
targetController = target
|
||||||
|
this.manga = manga
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
constructor(bundle: Bundle) : super(bundle) {
|
||||||
|
manga = Injekt.get<DatabaseHelper>().getManga(bundle.getLong(KEY_MANGA))
|
||||||
|
.executeAsBlocking()!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
|
val dialog = MaterialDialog(activity!!).apply {
|
||||||
|
customView(viewRes = R.layout.edit_manga_dialog, scrollable = true)
|
||||||
|
negativeButton(android.R.string.cancel)
|
||||||
|
positiveButton(R.string.action_save) { onPositiveButtonClick() }
|
||||||
|
}
|
||||||
|
dialogView = dialog.view
|
||||||
|
onViewCreated(dialog.view)
|
||||||
|
dialog.setOnShowListener {
|
||||||
|
val dView = (it as? MaterialDialog)?.view
|
||||||
|
dView?.contentLayout?.scrollView?.scrollTo(0, 0)
|
||||||
|
}
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onViewCreated(view: View) {
|
||||||
|
val mangaThumbnail = manga.toMangaThumbnail()
|
||||||
|
|
||||||
|
GlideApp.with(view.context)
|
||||||
|
.load(mangaThumbnail)
|
||||||
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
|
.centerCrop()
|
||||||
|
.into(view.manga_cover)
|
||||||
|
// view.manga_cover.loadAny(manga)
|
||||||
|
val isLocal = manga.source == LocalSource.ID
|
||||||
|
|
||||||
|
if (isLocal) {
|
||||||
|
if (manga.title != manga.url) {
|
||||||
|
view.title.append(manga.title)
|
||||||
|
}
|
||||||
|
view.title.hint = "${resources?.getString(R.string.title)}: ${manga.url}"
|
||||||
|
view.manga_author.append(manga.author ?: "")
|
||||||
|
view.manga_artist.append(manga.artist ?: "")
|
||||||
|
view.manga_description.append(manga.description ?: "")
|
||||||
|
view.manga_genres_tags.setChips(manga.genre?.split(", ") ?: emptyList())
|
||||||
|
} else {
|
||||||
|
if (manga.title != manga.originalTitle) {
|
||||||
|
view.title.append(manga.title)
|
||||||
|
}
|
||||||
|
if (manga.author != manga.originalAuthor) {
|
||||||
|
view.manga_author.append(manga.author ?: "")
|
||||||
|
}
|
||||||
|
if (manga.artist != manga.originalArtist) {
|
||||||
|
view.manga_artist.append(manga.artist ?: "")
|
||||||
|
}
|
||||||
|
if (manga.description != manga.originalDescription) {
|
||||||
|
view.manga_description.append(manga.description ?: "")
|
||||||
|
}
|
||||||
|
view.manga_genres_tags.setChips(manga.genre?.split(", ") ?: emptyList())
|
||||||
|
|
||||||
|
view.title.hint = "${resources?.getString(R.string.title)}: ${manga.originalTitle}"
|
||||||
|
if (manga.originalAuthor != null) {
|
||||||
|
view.manga_author.hint = "Author: ${manga.originalAuthor}"
|
||||||
|
}
|
||||||
|
if (manga.originalArtist != null) {
|
||||||
|
view.manga_artist.hint = "Artist: ${manga.originalArtist}"
|
||||||
|
}
|
||||||
|
if (manga.originalDescription != null) {
|
||||||
|
view.manga_description.hint =
|
||||||
|
"${resources?.getString(R.string.description)}: ${manga.originalDescription?.replace(
|
||||||
|
"\n", " "
|
||||||
|
)?.chop(20)}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
view.manga_genres_tags.clearFocus()
|
||||||
|
/*view.cover_layout.setOnClickListener {
|
||||||
|
infoController.changeCover()
|
||||||
|
}*/
|
||||||
|
view.reset_tags.setOnClickListener { resetTags() }
|
||||||
|
/*view.reset_cover.visibleIf(!isLocal)
|
||||||
|
view.reset_cover.setOnClickListener {
|
||||||
|
view.manga_cover.loadAny(manga, builder = {
|
||||||
|
parameters(Parameters.Builder().set(MangaFetcher.realCover, true).build())
|
||||||
|
})
|
||||||
|
willResetCover = true
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetTags() {
|
||||||
|
if (manga.genre.isNullOrBlank() || manga.source == LocalSource.ID) dialogView?.manga_genres_tags?.setChips(
|
||||||
|
emptyList()
|
||||||
|
)
|
||||||
|
else dialogView?.manga_genres_tags?.setChips(manga.originalGenre?.split(", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fun updateCover(uri: Uri) {
|
||||||
|
willResetCover = false
|
||||||
|
dialogView!!.manga_cover.loadAny(uri)
|
||||||
|
customCoverUri = uri
|
||||||
|
}*/
|
||||||
|
|
||||||
|
override fun onDestroyView(view: View) {
|
||||||
|
super.onDestroyView(view)
|
||||||
|
dialogView = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onPositiveButtonClick() {
|
||||||
|
infoController.presenter.updateMangaInfo(
|
||||||
|
dialogView?.title?.text.toString(),
|
||||||
|
dialogView?.manga_author?.text.toString(), dialogView?.manga_artist?.text.toString(),
|
||||||
|
dialogView?.manga_description?.text.toString()
|
||||||
|
)
|
||||||
|
// ,
|
||||||
|
// dialogView?.manga_genres_tags?.tags)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getAllChips() {
|
||||||
|
dialogView?.manga_genres_tags?.childCount
|
||||||
|
|
||||||
|
/*for (i in 0 until dialogView?.manga_genres_tags?.childCount) {
|
||||||
|
val child: View = getChildAt(i)
|
||||||
|
if (child is Chip) {
|
||||||
|
if (child.isChecked) {
|
||||||
|
checkedIds.add(child.getId())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val KEY_MANGA = "manga_id"
|
||||||
|
}
|
||||||
|
}
|
@ -161,6 +161,8 @@ class MangaAllInOneController :
|
|||||||
val smartSearchConfig: SourceController.SmartSearchConfig? = args.getParcelable(SMART_SEARCH_CONFIG_EXTRA)
|
val smartSearchConfig: SourceController.SmartSearchConfig? = args.getParcelable(SMART_SEARCH_CONFIG_EXTRA)
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext = Job() + Dispatchers.Main
|
override val coroutineContext: CoroutineContext = Job() + Dispatchers.Main
|
||||||
|
|
||||||
|
private var editMangaDialog: EditMangaDialog? = null
|
||||||
// EXH <--
|
// EXH <--
|
||||||
|
|
||||||
val fromSource = args.getBoolean(FROM_SOURCE_EXTRA, false)
|
val fromSource = args.getBoolean(FROM_SOURCE_EXTRA, false)
|
||||||
@ -666,6 +668,8 @@ class MangaAllInOneController :
|
|||||||
else -> throw NotImplementedError("Unimplemented sorting method")
|
else -> throw NotImplementedError("Unimplemented sorting method")
|
||||||
}
|
}
|
||||||
menu.findItem(sortingItem).isChecked = true
|
menu.findItem(sortingItem).isChecked = true
|
||||||
|
|
||||||
|
if (presenter.manga.favorite) menu.findItem(R.id.action_edit).isVisible = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
@ -720,6 +724,12 @@ class MangaAllInOneController :
|
|||||||
presenter.removeFilters()
|
presenter.removeFilters()
|
||||||
activity?.invalidateOptionsMenu()
|
activity?.invalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
R.id.action_edit -> {
|
||||||
|
editMangaDialog = EditMangaDialog(
|
||||||
|
this, presenter.manga
|
||||||
|
)
|
||||||
|
editMangaDialog?.showDialog(router)
|
||||||
|
}
|
||||||
R.id.action_sort -> presenter.revertSortOrder()
|
R.id.action_sort -> presenter.revertSortOrder()
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
|
@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.data.library.CustomMangaManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
@ -31,6 +32,7 @@ import exh.debug.DebugToggles
|
|||||||
import exh.eh.EHentaiUpdateHelper
|
import exh.eh.EHentaiUpdateHelper
|
||||||
import exh.isEhBasedSource
|
import exh.isEhBasedSource
|
||||||
import exh.util.await
|
import exh.util.await
|
||||||
|
import exh.util.trimOrNull
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -76,6 +78,8 @@ class MangaAllInOnePresenter(
|
|||||||
|
|
||||||
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||||
|
|
||||||
|
private val customMangaManager: CustomMangaManager by injectLazy()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the chapter list has been requested to the source.
|
* Whether the chapter list has been requested to the source.
|
||||||
*/
|
*/
|
||||||
@ -196,6 +200,47 @@ class MangaAllInOnePresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateMangaInfo(
|
||||||
|
title: String?,
|
||||||
|
author: String?,
|
||||||
|
artist: String?,
|
||||||
|
description: String?
|
||||||
|
// tags: Array<String>?
|
||||||
|
) {
|
||||||
|
if (manga.source == LocalSource.ID) {
|
||||||
|
manga.title = if (title.isNullOrBlank()) manga.url else title.trim()
|
||||||
|
manga.author = author?.trimOrNull()
|
||||||
|
manga.artist = artist?.trimOrNull()
|
||||||
|
manga.description = description?.trimOrNull()
|
||||||
|
/*val tagsString = tags?.joinToString(", ") { it.capitalize() }*/
|
||||||
|
/*manga.genre = if (tags.isNullOrEmpty()) null else tagsString?.trim()*/
|
||||||
|
LocalSource(downloadManager.context).updateMangaInfo(manga)
|
||||||
|
db.updateMangaInfo(manga).executeAsBlocking()
|
||||||
|
} else {
|
||||||
|
/*val genre = if (!tags.isNullOrEmpty() && tags.joinToString(", ") != manga.genre) {
|
||||||
|
tags.map { it.capitalize() }.toTypedArray()
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}*/
|
||||||
|
val manga = CustomMangaManager.MangaJson(
|
||||||
|
manga.id!!,
|
||||||
|
title?.trimOrNull(),
|
||||||
|
author?.trimOrNull(),
|
||||||
|
artist?.trimOrNull(),
|
||||||
|
description?.trimOrNull()
|
||||||
|
// genre
|
||||||
|
)
|
||||||
|
customMangaManager.saveMangaInfo(manga)
|
||||||
|
}
|
||||||
|
/*if (uri != null) {
|
||||||
|
editCoverWithStream(uri)
|
||||||
|
} else if (resetCover) {
|
||||||
|
coverCache.deleteCustomCover(manga)
|
||||||
|
controller.setPaletteColor()
|
||||||
|
}*/
|
||||||
|
// controller.updateHeader()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch manga information from source.
|
* Fetch manga information from source.
|
||||||
*/
|
*/
|
||||||
|
@ -7,3 +7,8 @@ fun List<String>.dropEmpty() = filter { it.isNotEmpty() }
|
|||||||
fun String.removeArticles(): String {
|
fun String.removeArticles(): String {
|
||||||
return this.replace(Regex("^(an|a|the) ", RegexOption.IGNORE_CASE), "")
|
return this.replace(Regex("^(an|a|the) ", RegexOption.IGNORE_CASE), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.trimOrNull(): String? {
|
||||||
|
val trimmed = trim()
|
||||||
|
return if (trimmed.isBlank()) null else trimmed
|
||||||
|
}
|
||||||
|
101
app/src/main/res/layout/edit_manga_dialog.xml
Normal file
101
app/src/main/res/layout/edit_manga_dialog.xml
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/cover_layout"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:layout_marginBottom="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/manga_cover"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:minWidth="75dp"
|
||||||
|
android:layout_height="150dp"
|
||||||
|
android:contentDescription="@string/description_cover"
|
||||||
|
android:background="@drawable/rounded_rectangle"
|
||||||
|
android:src="@mipmap/ic_launcher"/>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!--<Button
|
||||||
|
android:id="@+id/reset_cover"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/Theme.Widget"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="@string/reset_cover" />-->
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/title"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"/>
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/manga_author"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Artist"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/manga_artist"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="Author"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/manga_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:hint="@string/description"
|
||||||
|
android:inputType="text|textMultiLine"
|
||||||
|
android:scrollHorizontally="false" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/manga_genres_tags"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/reset_tags"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:text="Clear Tags" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?android:attr/divider"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -95,4 +95,11 @@
|
|||||||
android:title="@string/download_all" />
|
android:title="@string/download_all" />
|
||||||
</menu>
|
</menu>
|
||||||
</item>
|
</item>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_edit"
|
||||||
|
android:icon="@drawable/ic_edit_24dp"
|
||||||
|
android:title="@string/action_edit"
|
||||||
|
android:visible="false"
|
||||||
|
app:showAsAction="never" />
|
||||||
</menu>
|
</menu>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user