mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-09-10 20:43:14 +02:00
UI/Functionality for custom info done
Local Manga is up next
This commit is contained in:
parent
a94d455e79
commit
c92b2bb203
@ -211,7 +211,7 @@ dependencies {
|
|||||||
implementation 'me.zhanghai.android.systemuihelper:library:1.0.0'
|
implementation 'me.zhanghai.android.systemuihelper:library:1.0.0'
|
||||||
implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0'
|
implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0'
|
||||||
implementation 'com.github.mthli:Slice:v1.2'
|
implementation 'com.github.mthli:Slice:v1.2'
|
||||||
implementation 'me.gujun.android.taggroup:library:1.4@aar'
|
implementation 'com.github.kizitonwose:AndroidTagGroup:1.6.0'
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
implementation 'com.github.carlosesco:DirectionalViewPager:a844dbca0a'
|
implementation 'com.github.carlosesco:DirectionalViewPager:a844dbca0a'
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ object MangaTypeAdapter {
|
|||||||
write {
|
write {
|
||||||
beginArray()
|
beginArray()
|
||||||
value(it.url)
|
value(it.url)
|
||||||
value(it.trueTitle())
|
value(it.originalTitle())
|
||||||
value(it.source)
|
value(it.source)
|
||||||
value(it.viewer)
|
value(it.viewer)
|
||||||
value(it.chapter_flags)
|
value(it.chapter_flags)
|
||||||
|
@ -36,15 +36,12 @@ open class MangaImpl : Manga {
|
|||||||
|
|
||||||
override var hide_title: Boolean = false
|
override var hide_title: Boolean = false
|
||||||
|
|
||||||
var last_cover_fetch: Long = 0
|
|
||||||
|
|
||||||
override fun copyFrom(other: SManga) {
|
override fun copyFrom(other: SManga) {
|
||||||
if (((other is MangaImpl && (other as MangaImpl)::title.isInitialized)
|
if ((other is MangaImpl && (other as MangaImpl)::title.isInitialized && other.title != title)) {
|
||||||
|| other !is MangaImpl) && other.title != title) {
|
title = if (currentTitle() != originalTitle()) {
|
||||||
title = if (customTitle() != trueTitle()) {
|
val customTitle = currentTitle()
|
||||||
val customTitle = customTitle()
|
|
||||||
val trueTitle = other.title
|
val trueTitle = other.title
|
||||||
"${customTitle}≡§${trueTitle}"
|
"${customTitle}${SManga.splitter}${trueTitle}"
|
||||||
} else other.title
|
} else other.title
|
||||||
}
|
}
|
||||||
super.copyFrom(other)
|
super.copyFrom(other)
|
||||||
@ -64,4 +61,14 @@ open class MangaImpl : Manga {
|
|||||||
return url.hashCode()
|
return url.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private var lastCoverFetch:MutableMap<Long, Long> = mutableMapOf()
|
||||||
|
|
||||||
|
fun setLastCoverFetch(id: Long, time: Long) {
|
||||||
|
lastCoverFetch[id] = time
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLastCoverFetch(id: Long) = lastCoverFetch[id] ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,6 +92,16 @@ interface MangaQueries : DbProvider {
|
|||||||
.withPutResolver(MangaTitlePutResolver())
|
.withPutResolver(MangaTitlePutResolver())
|
||||||
.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()
|
||||||
|
|
||||||
fun deleteManga(manga: Manga) = db.delete().`object`(manga).prepare()
|
fun deleteManga(manga: Manga) = db.delete().`object`(manga).prepare()
|
||||||
|
|
||||||
fun deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()
|
fun deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
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.title)
|
||||||
|
put(MangaTable.COL_GENRE, manga.genre)
|
||||||
|
put(MangaTable.COL_AUTHOR, manga.author)
|
||||||
|
put(MangaTable.COL_ARTIST, manga.artist)
|
||||||
|
put(MangaTable.COL_DESCRIPTION, manga.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetToContentValues(manga: Manga) = ContentValues(1).apply {
|
||||||
|
put(MangaTable.COL_TITLE, manga.originalTitle())
|
||||||
|
put(MangaTable.COL_GENRE, manga.originalGenres())
|
||||||
|
put(MangaTable.COL_AUTHOR, manga.originalAuthor())
|
||||||
|
put(MangaTable.COL_ARTIST, manga.originalArtist())
|
||||||
|
put(MangaTable.COL_DESCRIPTION, manga.originalDesc())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -106,7 +106,7 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
NotificationReceiver.pauseDownloadsPendingBroadcast(context))
|
NotificationReceiver.pauseDownloadsPendingBroadcast(context))
|
||||||
}
|
}
|
||||||
|
|
||||||
val title = download.manga.customTitle().chop(15)
|
val title = download.manga.currentTitle().chop(15)
|
||||||
val quotedTitle = Pattern.quote(title)
|
val quotedTitle = Pattern.quote(title)
|
||||||
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
||||||
setContentTitle("$title - $chapter".chop(30))
|
setContentTitle("$title - $chapter".chop(30))
|
||||||
@ -161,7 +161,7 @@ internal class DownloadNotifier(private val context: Context) {
|
|||||||
}
|
}
|
||||||
// Create notification.
|
// Create notification.
|
||||||
with(notification) {
|
with(notification) {
|
||||||
val title = download.manga.customTitle().chop(15)
|
val title = download.manga.currentTitle().chop(15)
|
||||||
val quotedTitle = Pattern.quote(title)
|
val quotedTitle = Pattern.quote(title)
|
||||||
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
|
||||||
setContentTitle("$title - $chapter".chop(30))
|
setContentTitle("$title - $chapter".chop(30))
|
||||||
|
@ -178,7 +178,7 @@ class DownloadProvider(private val context: Context) {
|
|||||||
* @param manga the manga to query.
|
* @param manga the manga to query.
|
||||||
*/
|
*/
|
||||||
fun getMangaDirName(manga: Manga): String {
|
fun getMangaDirName(manga: Manga): String {
|
||||||
return DiskUtil.buildValidFilename(manga.trueTitle())
|
return DiskUtil.buildValidFilename(manga.originalTitle())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +36,7 @@ object LibraryUpdateRanker {
|
|||||||
fun lexicographicRanking(): Comparator<Manga> {
|
fun lexicographicRanking(): Comparator<Manga> {
|
||||||
return Comparator { mangaFirst: Manga,
|
return Comparator { mangaFirst: Manga,
|
||||||
mangaSecond: Manga ->
|
mangaSecond: Manga ->
|
||||||
compareValues(mangaFirst.customTitle(), mangaSecond.customTitle())
|
compareValues(mangaFirst.currentTitle(), mangaSecond.currentTitle())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.data.database.models.Category
|
|||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadService
|
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
@ -406,7 +407,7 @@ class LibraryUpdateService(
|
|||||||
manga.copyFrom(networkManga)
|
manga.copyFrom(networkManga)
|
||||||
db.insertManga(manga).executeAsBlocking()
|
db.insertManga(manga).executeAsBlocking()
|
||||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
manga.last_cover_fetch = Date().time
|
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
|
||||||
manga
|
manga
|
||||||
}
|
}
|
||||||
.onErrorReturn { manga }
|
.onErrorReturn { manga }
|
||||||
@ -461,7 +462,7 @@ class LibraryUpdateService(
|
|||||||
*/
|
*/
|
||||||
private fun showProgressNotification(manga: Manga, current: Int, total: Int) {
|
private fun showProgressNotification(manga: Manga, current: Int, total: Int) {
|
||||||
notificationManager.notify(Notifications.ID_LIBRARY_PROGRESS, progressNotification
|
notificationManager.notify(Notifications.ID_LIBRARY_PROGRESS, progressNotification
|
||||||
.setContentTitle(manga.customTitle())
|
.setContentTitle(manga.currentTitle())
|
||||||
.setProgress(total, current, false)
|
.setProgress(total, current, false)
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
@ -487,7 +488,7 @@ class LibraryUpdateService(
|
|||||||
}
|
}
|
||||||
catch (e: Exception) { }
|
catch (e: Exception) { }
|
||||||
setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
|
setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
|
||||||
setContentTitle(manga.customTitle())
|
setContentTitle(manga.currentTitle())
|
||||||
color = ContextCompat.getColor(this@LibraryUpdateService, R.color.colorAccentLight)
|
color = ContextCompat.getColor(this@LibraryUpdateService, R.color.colorAccentLight)
|
||||||
val chaptersNames = if (chapterNames.size > 5) {
|
val chaptersNames = if (chapterNames.size > 5) {
|
||||||
"${chapterNames.take(4).joinToString(", ")}, " +
|
"${chapterNames.take(4).joinToString(", ")}, " +
|
||||||
@ -527,11 +528,11 @@ class LibraryUpdateService(
|
|||||||
.notification_new_chapters_text,
|
.notification_new_chapters_text,
|
||||||
updates.size, updates.size))
|
updates.size, updates.size))
|
||||||
setStyle(NotificationCompat.BigTextStyle().bigText(updates.joinToString("\n") {
|
setStyle(NotificationCompat.BigTextStyle().bigText(updates.joinToString("\n") {
|
||||||
it.first.customTitle().chop(45)
|
it.first.currentTitle().chop(45)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setContentText(updates.first().first.customTitle().chop(45))
|
setContentText(updates.first().first.currentTitle().chop(45))
|
||||||
}
|
}
|
||||||
priority = NotificationCompat.PRIORITY_HIGH
|
priority = NotificationCompat.PRIORITY_HIGH
|
||||||
setGroup(Notifications.GROUP_NEW_CHAPTERS)
|
setGroup(Notifications.GROUP_NEW_CHAPTERS)
|
||||||
|
@ -11,7 +11,6 @@ import info.debatty.java.stringsimilarity.NormalizedLevenshtein
|
|||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.async
|
|
||||||
import kotlinx.coroutines.supervisorScope
|
import kotlinx.coroutines.supervisorScope
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
@ -65,7 +64,7 @@ class SmartSearchEngine(parentContext: CoroutineContext,
|
|||||||
return@supervisorScope listOf(SearchEntry(searchResults.mangas.first(), 0.0))
|
return@supervisorScope listOf(SearchEntry(searchResults.mangas.first(), 0.0))
|
||||||
|
|
||||||
searchResults.mangas.map {
|
searchResults.mangas.map {
|
||||||
val normalizedDistance = normalizedLevenshtein.similarity(title, it.trueTitle())
|
val normalizedDistance = normalizedLevenshtein.similarity(title, it.originalTitle())
|
||||||
SearchEntry(it, normalizedDistance)
|
SearchEntry(it, normalizedDistance)
|
||||||
}.filter { (_, normalizedDistance) ->
|
}.filter { (_, normalizedDistance) ->
|
||||||
normalizedDistance >= MIN_NORMAL_ELIGIBLE_THRESHOLD
|
normalizedDistance >= MIN_NORMAL_ELIGIBLE_THRESHOLD
|
||||||
|
@ -161,7 +161,7 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
} else {
|
} else {
|
||||||
chapterFile.nameWithoutExtension
|
chapterFile.nameWithoutExtension
|
||||||
}
|
}
|
||||||
val chapNameCut = chapName.replace(manga.trueTitle(), "", true).trim(' ', '-', '_')
|
val chapNameCut = chapName.replace(manga.originalTitle(), "", true).trim(' ', '-', '_')
|
||||||
name = if (chapNameCut.isEmpty()) chapName else chapNameCut
|
name = if (chapNameCut.isEmpty()) chapName else chapNameCut
|
||||||
date_upload = chapterFile.lastModified()
|
date_upload = chapterFile.lastModified()
|
||||||
ChapterRecognition.parseChapterNumber(this, manga)
|
ChapterRecognition.parseChapterNumber(this, manga)
|
||||||
|
@ -22,28 +22,84 @@ interface SManga : Serializable {
|
|||||||
|
|
||||||
var initialized: Boolean
|
var initialized: Boolean
|
||||||
|
|
||||||
fun customTitle(): String {
|
fun currentTitle(): String {
|
||||||
val splitTitle = title.split("▒")
|
val splitTitle = title.split(splitter)
|
||||||
return splitTitle.first()
|
return splitTitle.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun trueTitle(): String {
|
fun originalTitle(): String {
|
||||||
val splitTitle = title.split("▒")
|
val splitTitle = title.split(splitter)
|
||||||
return splitTitle.last()
|
return splitTitle.last()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun currentGenres(): String? {
|
||||||
|
val splitGenre = genre?.split(splitter) ?: return null
|
||||||
|
return splitGenre.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun originalGenres(): String? {
|
||||||
|
val splitGenre = genre?.split(splitter) ?: return null
|
||||||
|
return splitGenre.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun currentDesc(): String? {
|
||||||
|
val splitDesc = description?.split(splitter) ?: return null
|
||||||
|
return splitDesc.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun originalDesc(): String? {
|
||||||
|
val splitDesc = description?.split(splitter) ?: return null
|
||||||
|
return splitDesc.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun currentAuthor(): String? {
|
||||||
|
val splitAuth = author?.split(splitter) ?: return null
|
||||||
|
return splitAuth.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun originalAuthor(): String? {
|
||||||
|
val splitAuth = author?.split(splitter) ?: return null
|
||||||
|
return splitAuth.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun currentArtist(): String? {
|
||||||
|
val splitArtist = artist?.split(splitter) ?: return null
|
||||||
|
return splitArtist.first()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun originalArtist(): String? {
|
||||||
|
val splitArtist = artist?.split(splitter) ?: return null
|
||||||
|
return splitArtist.last()
|
||||||
|
}
|
||||||
|
|
||||||
fun copyFrom(other: SManga) {
|
fun copyFrom(other: SManga) {
|
||||||
if (other.author != null)
|
if (other.author != null)
|
||||||
author = other.author
|
author = if (currentAuthor() != originalAuthor()) {
|
||||||
|
val current = currentAuthor()
|
||||||
|
val og = other.author
|
||||||
|
"${current}$splitter${og}"
|
||||||
|
} else other.author
|
||||||
|
|
||||||
if (other.artist != null)
|
if (other.artist != null)
|
||||||
artist = other.artist
|
artist = if (currentArtist() != originalArtist()) {
|
||||||
|
val current = currentArtist()
|
||||||
|
val og = other.artist
|
||||||
|
"${current}$splitter${og}"
|
||||||
|
} else other.artist
|
||||||
|
|
||||||
if (other.description != null)
|
if (other.description != null)
|
||||||
description = other.description
|
description = if (currentDesc() != originalDesc()) {
|
||||||
|
val current = currentDesc()
|
||||||
|
val og = other.description
|
||||||
|
"${current}$splitter${og}"
|
||||||
|
} else other.description
|
||||||
|
|
||||||
if (other.genre != null)
|
if (other.genre != null)
|
||||||
genre = other.genre
|
genre = if (currentGenres() != originalGenres()) {
|
||||||
|
val current = currentGenres()
|
||||||
|
val og = other.genre
|
||||||
|
"${current}$splitter${og}"
|
||||||
|
} else other.genre
|
||||||
|
|
||||||
if (other.thumbnail_url != null)
|
if (other.thumbnail_url != null)
|
||||||
thumbnail_url = other.thumbnail_url
|
thumbnail_url = other.thumbnail_url
|
||||||
@ -59,6 +115,7 @@ 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
|
||||||
|
const val splitter = "▒ ▒∩▒"
|
||||||
|
|
||||||
fun create(): SManga {
|
fun create(): SManga {
|
||||||
return SMangaImpl()
|
return SMangaImpl()
|
||||||
|
@ -261,6 +261,7 @@ open class BrowseCataloguePresenter(
|
|||||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
val downloadManager: DownloadManager = Injekt.get()
|
val downloadManager: DownloadManager = Injekt.get()
|
||||||
downloadManager.deleteManga(manga,source)
|
downloadManager.deleteManga(manga,source)
|
||||||
|
db.resetMangaInfo(manga).executeAsBlocking()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,7 +29,7 @@ class CatalogueGridHolder(private val view: View, private val adapter: FlexibleA
|
|||||||
*/
|
*/
|
||||||
override fun onSetValues(manga: Manga) {
|
override fun onSetValues(manga: Manga) {
|
||||||
// Set manga title
|
// Set manga title
|
||||||
title.text = manga.title
|
title.text = manga.originalTitle()
|
||||||
|
|
||||||
// Set alpha of thumbnail.
|
// Set alpha of thumbnail.
|
||||||
thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f
|
thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f
|
||||||
|
@ -31,7 +31,7 @@ class CatalogueListHolder(private val view: View, adapter: FlexibleAdapter<IFlex
|
|||||||
* @param manga the manga to bind.
|
* @param manga the manga to bind.
|
||||||
*/
|
*/
|
||||||
override fun onSetValues(manga: Manga) {
|
override fun onSetValues(manga: Manga) {
|
||||||
title.text = manga.title
|
title.text = manga.originalTitle()
|
||||||
title.setTextColor(if (manga.favorite) favoriteColor else unfavoriteColor)
|
title.setTextColor(if (manga.favorite) favoriteColor else unfavoriteColor)
|
||||||
|
|
||||||
setImage(manga)
|
setImage(manga)
|
||||||
|
@ -38,7 +38,7 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
|
|||||||
chapter_title.text = download.chapter.name
|
chapter_title.text = download.chapter.name
|
||||||
|
|
||||||
// Update the manga title
|
// Update the manga title
|
||||||
manga_title.text = download.manga.customTitle()
|
manga_title.text = download.manga.currentTitle()
|
||||||
|
|
||||||
// Update the progress bar and the number of downloaded pages
|
// Update the progress bar and the number of downloaded pages
|
||||||
val pages = download.pages
|
val pages = download.pages
|
||||||
|
@ -1,25 +1,15 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
import android.graphics.Color
|
|
||||||
import android.text.format.DateUtils
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
|
||||||
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
|
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
|
||||||
import eu.kanade.tachiyomi.util.getResourceColor
|
|
||||||
import eu.kanade.tachiyomi.util.removeArticles
|
import eu.kanade.tachiyomi.util.removeArticles
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.text.DateFormat
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.Year
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
@ -94,7 +84,7 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) :
|
|||||||
"N/A"
|
"N/A"
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val title = (iFlexible as LibraryItem).manga.customTitle()
|
val title = (iFlexible as LibraryItem).manga.currentTitle()
|
||||||
if (preferences.removeArticles().getOrDefault())
|
if (preferences.removeArticles().getOrDefault())
|
||||||
title.removeArticles().substring(0, 1).toUpperCase(Locale.US)
|
title.removeArticles().substring(0, 1).toUpperCase(Locale.US)
|
||||||
else title.substring(0, 1).toUpperCase(Locale.US)
|
else title.substring(0, 1).toUpperCase(Locale.US)
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
@ -18,7 +15,6 @@ import android.view.inputmethod.InputMethodManager
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.content.ContextCompat.getSystemService
|
|
||||||
import androidx.core.graphics.drawable.DrawableCompat
|
import androidx.core.graphics.drawable.DrawableCompat
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
@ -57,15 +53,12 @@ import eu.kanade.tachiyomi.util.inflate
|
|||||||
import eu.kanade.tachiyomi.util.marginBottom
|
import eu.kanade.tachiyomi.util.marginBottom
|
||||||
import eu.kanade.tachiyomi.util.marginTop
|
import eu.kanade.tachiyomi.util.marginTop
|
||||||
import eu.kanade.tachiyomi.util.snack
|
import eu.kanade.tachiyomi.util.snack
|
||||||
import eu.kanade.tachiyomi.util.toast
|
|
||||||
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
||||||
import kotlinx.android.synthetic.main.library_controller.*
|
import kotlinx.android.synthetic.main.library_controller.*
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import timber.log.Timber
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class LibraryController(
|
class LibraryController(
|
||||||
bundle: Bundle? = null,
|
bundle: Bundle? = null,
|
||||||
@ -522,7 +515,6 @@ class LibraryController(
|
|||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
} else {
|
} else {
|
||||||
mode.title = resources?.getString(R.string.label_selected, count)
|
mode.title = resources?.getString(R.string.label_selected, count)
|
||||||
menu.findItem(R.id.action_edit_cover)?.isVisible = count == 1
|
|
||||||
menu.findItem(R.id.action_hide_title)?.isVisible =
|
menu.findItem(R.id.action_hide_title)?.isVisible =
|
||||||
!preferences.libraryAsList().getOrDefault()
|
!preferences.libraryAsList().getOrDefault()
|
||||||
if (!preferences.libraryAsList().getOrDefault()) {
|
if (!preferences.libraryAsList().getOrDefault()) {
|
||||||
@ -544,10 +536,6 @@ class LibraryController(
|
|||||||
|
|
||||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_edit_cover -> {
|
|
||||||
changeSelectedCover()
|
|
||||||
destroyActionModeIfNeeded()
|
|
||||||
}
|
|
||||||
R.id.action_move_to_category -> showChangeMangaCategoriesDialog()
|
R.id.action_move_to_category -> showChangeMangaCategoriesDialog()
|
||||||
R.id.action_delete -> deleteMangasFromLibrary()
|
R.id.action_delete -> deleteMangasFromLibrary()
|
||||||
R.id.action_select_all -> {
|
R.id.action_select_all -> {
|
||||||
@ -672,55 +660,6 @@ class LibraryController(
|
|||||||
presenter.moveMangasToCategories(categories, mangas)
|
presenter.moveMangasToCategories(categories, mangas)
|
||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Changes the cover for the selected manga.
|
|
||||||
*/
|
|
||||||
private fun changeSelectedCover() {
|
|
||||||
val manga = selectedMangas.firstOrNull() ?: return
|
|
||||||
selectedCoverManga = manga
|
|
||||||
|
|
||||||
if (manga.favorite) {
|
|
||||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
|
||||||
intent.type = "image/*"
|
|
||||||
startActivityForResult(Intent.createChooser(intent,
|
|
||||||
resources?.getString(R.string.file_select_cover)), REQUEST_IMAGE_OPEN)
|
|
||||||
} else {
|
|
||||||
activity?.toast(R.string.notification_first_add_to_library)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
if (requestCode == REQUEST_IMAGE_OPEN) {
|
|
||||||
if (data == null || resultCode != Activity.RESULT_OK) return
|
|
||||||
val activity = activity ?: return
|
|
||||||
val manga = selectedCoverManga ?: return
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Get the file's input stream from the incoming Intent
|
|
||||||
activity.contentResolver.openInputStream(data.data ?: Uri.EMPTY).use {
|
|
||||||
// Update cover to selected file, show error if something went wrong
|
|
||||||
if (it != null && presenter.editCoverWithStream(it, manga)) {
|
|
||||||
// TODO refresh cover
|
|
||||||
} else {
|
|
||||||
activity.toast(R.string.notification_cover_update_failed)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error: IOException) {
|
|
||||||
activity.toast(R.string.notification_cover_update_failed)
|
|
||||||
Timber.e(error)
|
|
||||||
}
|
|
||||||
selectedCoverManga = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
/**
|
|
||||||
* Key to change the cover of a manga in [onActivityResult].
|
|
||||||
*/
|
|
||||||
const val REQUEST_IMAGE_OPEN = 101
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
object HeightTopWindowInsetsListener : View.OnApplyWindowInsetsListener {
|
object HeightTopWindowInsetsListener : View.OnApplyWindowInsetsListener {
|
||||||
|
@ -6,9 +6,11 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|||||||
import com.bumptech.glide.signature.ObjectKey
|
import com.bumptech.glide.signature.ObjectKey
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.source.LocalSource
|
import eu.kanade.tachiyomi.source.LocalSource
|
||||||
import kotlinx.android.synthetic.main.catalogue_grid_item.*
|
import kotlinx.android.synthetic.main.catalogue_grid_item.*
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class used to hold the displayed data of a manga in the library, like the cover or the title.
|
* Class used to hold the displayed data of a manga in the library, like the cover or the title.
|
||||||
@ -35,7 +37,7 @@ class LibraryGridHolder(
|
|||||||
// Update the title of the manga.
|
// Update the title of the manga.
|
||||||
with(title) {
|
with(title) {
|
||||||
visibility = if (item.manga.hide_title) View.GONE else View.VISIBLE
|
visibility = if (item.manga.hide_title) View.GONE else View.VISIBLE
|
||||||
text = item.manga.customTitle()
|
text = item.manga.currentTitle()
|
||||||
}
|
}
|
||||||
gradient.visibility = if (item.manga.hide_title) View.GONE else View.VISIBLE
|
gradient.visibility = if (item.manga.hide_title) View.GONE else View.VISIBLE
|
||||||
|
|
||||||
@ -57,7 +59,7 @@ class LibraryGridHolder(
|
|||||||
GlideApp.with(view.context)
|
GlideApp.with(view.context)
|
||||||
.load(item.manga)
|
.load(item.manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.signature(ObjectKey(item.manga.last_cover_fetch.toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(item.manga.id!!).toString()))
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(thumbnail)
|
.into(thumbnail)
|
||||||
}
|
}
|
||||||
|
@ -71,13 +71,14 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference
|
|||||||
val sourceManager by injectLazy<SourceManager>()
|
val sourceManager by injectLazy<SourceManager>()
|
||||||
val sourceName = sourceManager.getOrStub(manga.source).name
|
val sourceName = sourceManager.getOrStub(manga.source).name
|
||||||
return manga.title.contains(constraint, true) ||
|
return manga.title.contains(constraint, true) ||
|
||||||
(manga.author?.contains(constraint, true) ?: false) ||
|
(manga.currentAuthor()?.contains(constraint, true) ?: false) ||
|
||||||
|
(manga.currentArtist()?.contains(constraint, true) ?: false) ||
|
||||||
sourceName.contains(constraint, true) ||
|
sourceName.contains(constraint, true) ||
|
||||||
if (constraint.contains(",")) {
|
if (constraint.contains(",")) {
|
||||||
val genres = manga.genre?.split(", ")
|
val genres = manga.currentGenres()?.split(", ")
|
||||||
constraint.split(",").all { containsGenre(it.trim(), genres) }
|
constraint.split(",").all { containsGenre(it.trim(), genres) }
|
||||||
}
|
}
|
||||||
else containsGenre(constraint, manga.genre?.split(", "))
|
else containsGenre(constraint, manga.currentGenres()?.split(", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
@SuppressLint("DefaultLocale")
|
||||||
|
@ -9,6 +9,7 @@ import kotlinx.android.synthetic.main.catalogue_list_item.*
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bumptech.glide.signature.ObjectKey
|
import com.bumptech.glide.signature.ObjectKey
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class used to hold the displayed data of a manga in the library, like the cover or the title.
|
* Class used to hold the displayed data of a manga in the library, like the cover or the title.
|
||||||
@ -33,7 +34,7 @@ class LibraryListHolder(
|
|||||||
*/
|
*/
|
||||||
override fun onSetValues(item: LibraryItem) {
|
override fun onSetValues(item: LibraryItem) {
|
||||||
// Update the title of the manga.
|
// Update the title of the manga.
|
||||||
title.text = item.manga.customTitle()
|
title.text = item.manga.currentTitle()
|
||||||
|
|
||||||
// Update the unread count and its visibility.
|
// Update the unread count and its visibility.
|
||||||
with(unread_text) {
|
with(unread_text) {
|
||||||
@ -59,7 +60,7 @@ class LibraryListHolder(
|
|||||||
GlideApp.with(itemView.context)
|
GlideApp.with(itemView.context)
|
||||||
.load(item.manga)
|
.load(item.manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.signature(ObjectKey(item.manga.last_cover_fetch.toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(item.manga.id!!).toString()))
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.circleCrop()
|
.circleCrop()
|
||||||
.dontAnimate()
|
.dontAnimate()
|
||||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.library
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.jakewharton.rxrelay.BehaviorRelay
|
import com.jakewharton.rxrelay.BehaviorRelay
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
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.database.models.Category
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
@ -280,8 +279,8 @@ class LibraryPresenter(
|
|||||||
|
|
||||||
private fun sortAlphabetical(i1: LibraryItem, i2: LibraryItem): Int {
|
private fun sortAlphabetical(i1: LibraryItem, i2: LibraryItem): Int {
|
||||||
return if (preferences.removeArticles().getOrDefault())
|
return if (preferences.removeArticles().getOrDefault())
|
||||||
i1.manga.customTitle().removeArticles().compareTo(i2.manga.customTitle().removeArticles(), true)
|
i1.manga.currentTitle().removeArticles().compareTo(i2.manga.currentTitle().removeArticles(), true)
|
||||||
else i1.manga.customTitle().compareTo(i2.manga.customTitle(), true)
|
else i1.manga.currentTitle().compareTo(i2.manga.currentTitle(), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -385,6 +384,7 @@ class LibraryPresenter(
|
|||||||
Observable.fromCallable {
|
Observable.fromCallable {
|
||||||
val mangaToDelete = mangas.distinctBy { it.id }
|
val mangaToDelete = mangas.distinctBy { it.id }
|
||||||
mangaToDelete.forEach { manga ->
|
mangaToDelete.forEach { manga ->
|
||||||
|
db.resetMangaInfo(manga).executeAsBlocking()
|
||||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
val source = sourceManager.get(manga.source) as? HttpSource
|
val source = sourceManager.get(manga.source) as? HttpSource
|
||||||
if (source != null)
|
if (source != null)
|
||||||
@ -503,27 +503,4 @@ class LibraryPresenter(
|
|||||||
db.updateMangaTitle(manga).executeAsBlocking()
|
db.updateMangaTitle(manga).executeAsBlocking()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Update cover with local file.
|
|
||||||
*
|
|
||||||
* @param inputStream the new cover.
|
|
||||||
* @param manga the manga edited.
|
|
||||||
* @return true if the cover is updated, false otherwise
|
|
||||||
*/
|
|
||||||
@Throws(IOException::class)
|
|
||||||
fun editCoverWithStream(inputStream: InputStream, manga: Manga): Boolean {
|
|
||||||
if (manga.source == LocalSource.ID) {
|
|
||||||
LocalSource.updateCover(context, manga, inputStream)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (manga.thumbnail_url != null && manga.favorite) {
|
|
||||||
coverCache.copyToCache(manga.thumbnail_url!!, inputStream)
|
|
||||||
(manga as? MangaImpl)?.last_cover_fetch = Date().time
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import eu.kanade.tachiyomi.ui.base.controller.RxController
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
|
import eu.kanade.tachiyomi.ui.base.controller.TabbedController
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
|
import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
|
||||||
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
|
||||||
import eu.kanade.tachiyomi.ui.main.SearchActivity
|
import eu.kanade.tachiyomi.ui.main.SearchActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersController
|
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersController
|
||||||
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
|
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
|
||||||
@ -116,7 +115,7 @@ class MangaController : RxController, TabbedController {
|
|||||||
private var trackingIconSubscription: Subscription? = null
|
private var trackingIconSubscription: Subscription? = null
|
||||||
|
|
||||||
override fun getTitle(): String? {
|
override fun getTitle(): String? {
|
||||||
return manga?.customTitle()
|
return manga?.currentTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||||
@ -156,6 +155,11 @@ class MangaController : RxController, TabbedController {
|
|||||||
else activity?.tabs
|
else activity?.tabs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateTitle(manga: Manga) {
|
||||||
|
this.manga?.title = manga.title
|
||||||
|
setTitle()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onChangeEnded(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
override fun onChangeEnded(handler: ControllerChangeHandler, type: ControllerChangeType) {
|
||||||
super.onChangeEnded(handler, type)
|
super.onChangeEnded(handler, type)
|
||||||
if (manga == null || source == null) {
|
if (manga == null || source == null) {
|
||||||
|
@ -1,59 +1,53 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga.info
|
package eu.kanade.tachiyomi.ui.manga.info
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
|
import android.content.Intent
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.WindowManager
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.materialdialogs.WhichButton
|
|
||||||
import com.afollestad.materialdialogs.actions.setActionButtonEnabled
|
|
||||||
import com.afollestad.materialdialogs.customview.customView
|
import com.afollestad.materialdialogs.customview.customView
|
||||||
import com.jakewharton.rxbinding.widget.itemClicks
|
import com.bluelinelabs.conductor.Router
|
||||||
import com.jakewharton.rxbinding.widget.textChanges
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
import com.bumptech.glide.signature.ObjectKey
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
import eu.kanade.tachiyomi.data.track.TrackService
|
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||||
import eu.kanade.tachiyomi.ui.manga.track.TrackController
|
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||||
import eu.kanade.tachiyomi.ui.manga.track.TrackSearchAdapter
|
import eu.kanade.tachiyomi.util.chop
|
||||||
import eu.kanade.tachiyomi.ui.manga.track.TrackSearchDialog
|
import eu.kanade.tachiyomi.util.toast
|
||||||
import eu.kanade.tachiyomi.util.plusAssign
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.*
|
||||||
import kotlinx.android.synthetic.main.track_controller.*
|
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_title
|
||||||
import kotlinx.android.synthetic.main.track_search_dialog.view.*
|
import me.gujun.android.taggroup.TagGroup
|
||||||
import rx.Subscription
|
import timber.log.Timber
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
|
||||||
import rx.subscriptions.CompositeSubscription
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.concurrent.TimeUnit
|
import java.io.IOException
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
class EditMangaDialog : DialogController {
|
class EditMangaDialog : DialogController {
|
||||||
|
|
||||||
private var dialogView: View? = null
|
private var dialogView: View? = null
|
||||||
|
|
||||||
private var adapter: TrackSearchAdapter? = null
|
|
||||||
|
|
||||||
private var selectedItem: Track? = null
|
|
||||||
|
|
||||||
private val manga: Manga
|
private val manga: Manga
|
||||||
|
|
||||||
private var subscriptions = CompositeSubscription()
|
private var customCoverUri:Uri? = null
|
||||||
|
|
||||||
private var searchTextSubscription: Subscription? = null
|
private val infoController
|
||||||
|
get() = targetController as MangaInfoController
|
||||||
|
|
||||||
private val trackController
|
constructor(target: MangaInfoController, manga: Manga) : super(Bundle()
|
||||||
get() = targetController as TrackController
|
|
||||||
|
|
||||||
private var wasPreviouslyTracked:Boolean = false
|
|
||||||
|
|
||||||
constructor(target: TrackController, manga: Manga, wasTracked:Boolean) : super(Bundle()
|
|
||||||
.apply {
|
.apply {
|
||||||
putLong(KEY_MANGA, manga.id!!)
|
putLong(KEY_MANGA, manga.id!!)
|
||||||
}) {
|
}) {
|
||||||
wasPreviouslyTracked = wasTracked
|
|
||||||
targetController = target
|
targetController = target
|
||||||
this.manga = manga
|
this.manga = manga
|
||||||
}
|
}
|
||||||
@ -64,101 +58,112 @@ class EditMangaDialog : DialogController {
|
|||||||
.executeAsBlocking()!!
|
.executeAsBlocking()!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showDialog(router: Router) {
|
||||||
|
super.showDialog(router)
|
||||||
|
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||||
val dialog = MaterialDialog(activity!!).apply {
|
val dialog = MaterialDialog(activity!!).apply {
|
||||||
customView(viewRes = R.layout.track_search_dialog, scrollable = false)
|
customView(viewRes = R.layout.edit_manga_dialog, scrollable = true)
|
||||||
negativeButton(android.R.string.cancel)
|
negativeButton(android.R.string.cancel)
|
||||||
positiveButton(
|
positiveButton(R.string.action_save) { onPositiveButtonClick() }
|
||||||
if (wasPreviouslyTracked) R.string.action_clear
|
|
||||||
else R.string.action_track){ onPositiveButtonClick() }
|
|
||||||
setActionButtonEnabled(WhichButton.POSITIVE, wasPreviouslyTracked)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subscriptions.isUnsubscribed) {
|
|
||||||
subscriptions = CompositeSubscription()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dialogView = dialog.view
|
dialogView = dialog.view
|
||||||
onViewCreated(dialog.view, savedViewState)
|
onViewCreated(dialog.view, savedViewState)
|
||||||
|
|
||||||
return dialog
|
return dialog
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onViewCreated(view: View, savedState: Bundle?) {
|
fun onViewCreated(view: View, savedState: Bundle?) {
|
||||||
// Create adapter
|
GlideApp.with(view.context)
|
||||||
val adapter = TrackSearchAdapter(view.context)
|
.asDrawable()
|
||||||
this.adapter = adapter
|
.load(manga)
|
||||||
view.track_search_list.adapter = adapter
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
||||||
|
.dontAnimate()
|
||||||
|
.into(view.manga_cover)
|
||||||
|
|
||||||
// Set listeners
|
if (manga.currentTitle() != manga.originalTitle())
|
||||||
selectedItem = null
|
view.manga_title.append(manga.currentTitle())
|
||||||
|
view.manga_title.hint = "${resources?.getString(R.string.title)}: ${manga.originalTitle()}"
|
||||||
|
|
||||||
subscriptions += view.track_search_list.itemClicks().subscribe { position ->
|
if (manga.currentAuthor() != manga.originalAuthor())
|
||||||
selectedItem = adapter.getItem(position)
|
view.manga_author.append(manga.currentAuthor())
|
||||||
(dialog as? MaterialDialog)?.positiveButton(R.string.action_track)
|
if (!manga.originalAuthor().isNullOrBlank())
|
||||||
(dialog as? MaterialDialog)?.setActionButtonEnabled(WhichButton.POSITIVE, true)
|
view.manga_author.hint = "${resources?.getString(R.string.manga_info_author_label)}: ${manga.originalAuthor()}"
|
||||||
|
|
||||||
|
if (manga.currentArtist() != manga.originalArtist())
|
||||||
|
view.manga_artist.append(manga.currentArtist())
|
||||||
|
if (!manga.originalArtist().isNullOrBlank())
|
||||||
|
view.manga_artist.hint = "${resources?.getString(R.string.manga_info_artist_label)}: ${manga.originalArtist()}"
|
||||||
|
|
||||||
|
view.cover_layout.setOnClickListener {
|
||||||
|
changeCover()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do an initial search based on the manga's title
|
if (manga.currentArtist() != manga.originalArtist())
|
||||||
if (savedState == null) {
|
view.manga_description.append(manga.currentDesc())
|
||||||
val title = trackController.presenter.manga.trueTitle()
|
if (!manga.originalDesc().isNullOrBlank())
|
||||||
view.track_search.append(title)
|
view.manga_description.hint = "${resources?.getString(R.string.description)}: ${manga
|
||||||
search(title)
|
.originalDesc()?.chop(15)}"
|
||||||
|
if (manga.currentGenres().isNullOrBlank().not()) {
|
||||||
|
view.manga_genres_tags.setTags(manga.currentGenres()?.split(", "))
|
||||||
|
}
|
||||||
|
view.reset_tags.setOnClickListener { resetTags() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resetTags() {
|
||||||
|
if (manga.originalGenres().isNullOrBlank() || manga.originalGenres() == "null")
|
||||||
|
dialogView?.manga_genres_tags?.setTags(emptyList())
|
||||||
|
else
|
||||||
|
dialogView?.manga_genres_tags?.setTags(manga.originalGenres()?.split(", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeCover() {
|
||||||
|
if (manga.favorite) {
|
||||||
|
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||||
|
intent.type = "image/*"
|
||||||
|
startActivityForResult(
|
||||||
|
Intent.createChooser(intent,
|
||||||
|
resources?.getString(R.string.file_select_cover)),
|
||||||
|
101
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
activity?.toast(R.string.notification_first_add_to_library)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == 101) {
|
||||||
|
if (data == null || resultCode != Activity.RESULT_OK) return
|
||||||
|
val activity = activity ?: return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get the file's input stream from the incoming Intent
|
||||||
|
GlideApp.with(dialogView!!.context)
|
||||||
|
.load(data.data ?: Uri.EMPTY)
|
||||||
|
.into(dialogView!!.manga_cover)
|
||||||
|
customCoverUri = data.data
|
||||||
|
} catch (error: IOException) {
|
||||||
|
activity.toast(R.string.notification_cover_update_failed)
|
||||||
|
Timber.e(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onDestroyView(view: View) {
|
override fun onDestroyView(view: View) {
|
||||||
super.onDestroyView(view)
|
super.onDestroyView(view)
|
||||||
subscriptions.unsubscribe()
|
|
||||||
dialogView = null
|
dialogView = null
|
||||||
adapter = null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onAttach(view: View) {
|
|
||||||
super.onAttach(view)
|
|
||||||
searchTextSubscription = dialogView!!.track_search.textChanges()
|
|
||||||
.skip(1)
|
|
||||||
.debounce(1, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
|
|
||||||
.map { it.toString() }
|
|
||||||
.filter(String::isNotBlank)
|
|
||||||
.subscribe { search(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDetach(view: View) {
|
|
||||||
super.onDetach(view)
|
|
||||||
searchTextSubscription?.unsubscribe()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun search(query: String) {
|
|
||||||
val view = dialogView ?: return
|
|
||||||
view.progress.visibility = View.VISIBLE
|
|
||||||
view.track_search_list.visibility = View.INVISIBLE
|
|
||||||
//trackController.presenter.search(query, service)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onSearchResults(results: List<TrackSearch>) {
|
|
||||||
selectedItem = null
|
|
||||||
val view = dialogView ?: return
|
|
||||||
view.progress.visibility = View.INVISIBLE
|
|
||||||
view.track_search_list.visibility = View.VISIBLE
|
|
||||||
adapter?.setItems(results)
|
|
||||||
if (results.size == 1 && !wasPreviouslyTracked) {
|
|
||||||
selectedItem = adapter?.getItem(0)
|
|
||||||
(dialog as? MaterialDialog)?.positiveButton(R.string.action_track)
|
|
||||||
(dialog as? MaterialDialog)?.setActionButtonEnabled(WhichButton.POSITIVE, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onSearchResultsError() {
|
|
||||||
val view = dialogView ?: return
|
|
||||||
view.progress.visibility = View.VISIBLE
|
|
||||||
view.track_search_list.visibility = View.INVISIBLE
|
|
||||||
adapter?.setItems(emptyList())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onPositiveButtonClick() {
|
private fun onPositiveButtonClick() {
|
||||||
//trackController.swipe_refresh.isRefreshing = true
|
infoController.presenter.updateManga(dialogView?.manga_title?.text.toString(),
|
||||||
//trackController.presenter.registerTracking(selectedItem, service)
|
dialogView?.manga_author?.text.toString(), dialogView?.manga_artist?.text.toString(),
|
||||||
|
customCoverUri, dialogView?.manga_description?.text.toString(),
|
||||||
|
dialogView?.manga_genres_tags?.tags)
|
||||||
|
infoController.updateTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
|
@ -70,8 +70,9 @@ import eu.kanade.tachiyomi.util.updateLayoutParams
|
|||||||
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
||||||
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
||||||
import jp.wasabeef.glide.transformations.MaskTransformation
|
import jp.wasabeef.glide.transformations.MaskTransformation
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
|
||||||
import kotlinx.android.synthetic.main.manga_info_controller.*
|
import kotlinx.android.synthetic.main.manga_info_controller.*
|
||||||
|
import kotlinx.android.synthetic.main.manga_info_controller.manga_cover
|
||||||
|
import kotlinx.android.synthetic.main.manga_info_controller.manga_genres_tags
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.DateFormat
|
import java.text.DateFormat
|
||||||
@ -181,7 +182,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
shortAnimationDuration = resources?.getInteger(android.R.integer.config_shortAnimTime) ?: 0
|
shortAnimationDuration = resources?.getInteger(android.R.integer.config_shortAnimTime) ?: 0
|
||||||
|
|
||||||
manga_cover.longClicks().subscribeUntilDestroy {
|
manga_cover.longClicks().subscribeUntilDestroy {
|
||||||
copyToClipboard(view.context.getString(R.string.title), presenter.manga.customTitle(), R.string
|
copyToClipboard(view.context.getString(R.string.title), presenter.manga.currentTitle(), R.string
|
||||||
.manga_info_full_title_label)
|
.manga_info_full_title_label)
|
||||||
}
|
}
|
||||||
container = (view as ViewGroup).findViewById(R.id.manga_info_layout) as? View
|
container = (view as ViewGroup).findViewById(R.id.manga_info_layout) as? View
|
||||||
@ -219,11 +220,14 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
inflater.inflate(R.menu.manga_info, menu)
|
inflater.inflate(R.menu.manga_info, menu)
|
||||||
|
|
||||||
|
val editItem = menu.findItem(R.id.action_edit)
|
||||||
|
editItem.isVisible = presenter.manga.favorite
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_edit -> { }
|
R.id.action_edit -> EditMangaDialog(this, presenter.manga).showDialog(router)
|
||||||
R.id.action_open_in_browser -> openInBrowser()
|
R.id.action_open_in_browser -> openInBrowser()
|
||||||
R.id.action_open_in_web_view -> openInWebView()
|
R.id.action_open_in_web_view -> openInWebView()
|
||||||
R.id.action_share -> prepareToShareManga()
|
R.id.action_share -> prepareToShareManga()
|
||||||
@ -262,39 +266,39 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
val view = view ?: return
|
val view = view ?: return
|
||||||
|
|
||||||
//update full title TextView.
|
//update full title TextView.
|
||||||
manga_full_title.text = if (manga.customTitle().isBlank()) {
|
manga_full_title.text = if (manga.currentTitle().isBlank()) {
|
||||||
view.context.getString(R.string.unknown)
|
view.context.getString(R.string.unknown)
|
||||||
} else {
|
} else {
|
||||||
manga.customTitle()
|
manga.currentTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update artist TextView.
|
// Update artist TextView.
|
||||||
manga_artist.text = if (manga.artist.isNullOrBlank()) {
|
manga_artist.text = if (manga.currentArtist().isNullOrBlank()) {
|
||||||
view.context.getString(R.string.unknown)
|
view.context.getString(R.string.unknown)
|
||||||
} else {
|
} else {
|
||||||
manga.artist
|
manga.currentArtist()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update author TextView.
|
// Update author TextView.
|
||||||
manga_author.text = if (manga.author.isNullOrBlank()) {
|
manga_author.text = if (manga.currentAuthor().isNullOrBlank()) {
|
||||||
view.context.getString(R.string.unknown)
|
view.context.getString(R.string.unknown)
|
||||||
} else {
|
} else {
|
||||||
manga.author
|
manga.currentAuthor()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If manga source is known update source TextView.
|
// If manga source is known update source TextView.
|
||||||
manga_source.text = source?.toString() ?: view.context.getString(R.string.unknown)
|
manga_source.text = source?.toString() ?: view.context.getString(R.string.unknown)
|
||||||
|
|
||||||
// Update genres list
|
// Update genres list
|
||||||
if (manga.genre.isNullOrBlank().not()) {
|
if (manga.currentGenres().isNullOrBlank().not()) {
|
||||||
manga_genres_tags.setTags(manga.genre?.split(", "))
|
manga_genres_tags.setTags(manga.currentGenres()?.split(", "))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update description TextView.
|
// Update description TextView.
|
||||||
manga_summary.text = if (manga.description.isNullOrBlank()) {
|
manga_summary.text = if (manga.currentDesc().isNullOrBlank()) {
|
||||||
view.context.getString(R.string.unknown)
|
view.context.getString(R.string.unknown)
|
||||||
} else {
|
} else {
|
||||||
manga.description
|
manga.currentDesc()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update status TextView.
|
// Update status TextView.
|
||||||
@ -307,19 +311,20 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
|
|
||||||
// Set the favorite drawable to the correct one.
|
// Set the favorite drawable to the correct one.
|
||||||
setFavoriteDrawable(manga.favorite)
|
setFavoriteDrawable(manga.favorite)
|
||||||
|
activity?.invalidateOptionsMenu()
|
||||||
|
|
||||||
// Set cover if it wasn't already.
|
// Set cover if it wasn't already.
|
||||||
if (!manga.thumbnail_url.isNullOrEmpty()) {
|
if (!manga.thumbnail_url.isNullOrEmpty()) {
|
||||||
GlideApp.with(view.context)
|
GlideApp.with(view.context)
|
||||||
.load(manga)
|
.load(manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.signature(ObjectKey((manga as MangaImpl).last_cover_fetch.toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
||||||
//.centerCrop()
|
//.centerCrop()
|
||||||
.into(manga_cover)
|
.into(manga_cover)
|
||||||
if (manga_cover_full != null) {
|
if (manga_cover_full != null) {
|
||||||
GlideApp.with(view.context).asDrawable().load(manga)
|
GlideApp.with(view.context).asDrawable().load(manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.signature(ObjectKey(manga.last_cover_fetch.toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
||||||
.override(CustomTarget.SIZE_ORIGINAL, CustomTarget.SIZE_ORIGINAL)
|
.override(CustomTarget.SIZE_ORIGINAL, CustomTarget.SIZE_ORIGINAL)
|
||||||
.into(object : CustomTarget<Drawable>() {
|
.into(object : CustomTarget<Drawable>() {
|
||||||
override fun onResourceReady(resource: Drawable,
|
override fun onResourceReady(resource: Drawable,
|
||||||
@ -336,7 +341,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
GlideApp.with(view.context)
|
GlideApp.with(view.context)
|
||||||
.load(manga)
|
.load(manga)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||||
.signature(ObjectKey(manga.last_cover_fetch.toString()))
|
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(backdrop)
|
.into(backdrop)
|
||||||
}
|
}
|
||||||
@ -397,7 +402,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
val activity = activity ?: return
|
val activity = activity ?: return
|
||||||
val intent = WebViewActivity.newIntent(activity, source.id, url, presenter.manga.trueTitle())
|
val intent = WebViewActivity.newIntent(activity, source.id, url, presenter.manga.originalTitle())
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,7 +438,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
val intent = Intent(Intent.ACTION_SEND).apply {
|
val intent = Intent(Intent.ACTION_SEND).apply {
|
||||||
type = "text/*"
|
type = "text/*"
|
||||||
putExtra(Intent.EXTRA_TEXT, url)
|
putExtra(Intent.EXTRA_TEXT, url)
|
||||||
putExtra(Intent.EXTRA_TITLE, presenter.manga.customTitle())
|
putExtra(Intent.EXTRA_TITLE, presenter.manga.currentTitle())
|
||||||
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
clipData = ClipData.newRawUri(null, stream)
|
clipData = ClipData.newRawUri(null, stream)
|
||||||
@ -710,11 +715,11 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
|
|
||||||
// Check if shortcut placement is supported
|
// Check if shortcut placement is supported
|
||||||
if (ShortcutManagerCompat.isRequestPinShortcutSupported(activity)) {
|
if (ShortcutManagerCompat.isRequestPinShortcutSupported(activity)) {
|
||||||
val shortcutId = "manga-shortcut-${presenter.manga.trueTitle()}-${presenter.source.name}"
|
val shortcutId = "manga-shortcut-${presenter.manga.originalTitle()}-${presenter.source.name}"
|
||||||
|
|
||||||
// Create shortcut info
|
// Create shortcut info
|
||||||
val shortcutInfo = ShortcutInfoCompat.Builder(activity, shortcutId)
|
val shortcutInfo = ShortcutInfoCompat.Builder(activity, shortcutId)
|
||||||
.setShortLabel(presenter.manga.customTitle())
|
.setShortLabel(presenter.manga.currentTitle())
|
||||||
.setIcon(IconCompat.createWithBitmap(icon))
|
.setIcon(IconCompat.createWithBitmap(icon))
|
||||||
.setIntent(shortcutIntent)
|
.setIntent(shortcutIntent)
|
||||||
.build()
|
.build()
|
||||||
@ -735,6 +740,11 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateTitle() {
|
||||||
|
setMangaInfo(presenter.manga, presenter.source)
|
||||||
|
(parentController as? MangaController)?.updateTitle(presenter.manga)
|
||||||
|
}
|
||||||
|
|
||||||
private fun setFullCoverToThumb() {
|
private fun setFullCoverToThumb() {
|
||||||
if (setUpFullCover) return
|
if (setUpFullCover) return
|
||||||
val expandedImageView = manga_cover_full ?: return
|
val expandedImageView = manga_cover_full ?: return
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.manga.info
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.jakewharton.rxrelay.BehaviorRelay
|
import com.jakewharton.rxrelay.BehaviorRelay
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
@ -12,10 +13,11 @@ 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.database.models.MangaImpl
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
|
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.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import eu.kanade.tachiyomi.util.DiskUtil
|
import eu.kanade.tachiyomi.util.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.ImageUtil
|
|
||||||
import eu.kanade.tachiyomi.util.isNullOrUnsubscribed
|
import eu.kanade.tachiyomi.util.isNullOrUnsubscribed
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
@ -24,7 +26,6 @@ import rx.schedulers.Schedulers
|
|||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
@ -94,7 +95,7 @@ class MangaInfoPresenter(
|
|||||||
manga.initialized = true
|
manga.initialized = true
|
||||||
db.insertManga(manga).executeAsBlocking()
|
db.insertManga(manga).executeAsBlocking()
|
||||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
(manga as? MangaImpl)?.last_cover_fetch = Date().time
|
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
|
||||||
manga
|
manga
|
||||||
}
|
}
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
@ -119,6 +120,7 @@ class MangaInfoPresenter(
|
|||||||
|
|
||||||
fun confirmDeletion() {
|
fun confirmDeletion() {
|
||||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
|
db.resetMangaInfo(manga).executeAsBlocking()
|
||||||
downloadManager.deleteManga(manga, source)
|
downloadManager.deleteManga(manga, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +150,7 @@ class MangaInfoPresenter(
|
|||||||
directory.mkdirs()
|
directory.mkdirs()
|
||||||
|
|
||||||
// Build destination file.
|
// Build destination file.
|
||||||
val filename = DiskUtil.buildValidFilename("${manga.trueTitle()} - Cover.jpg")
|
val filename = DiskUtil.buildValidFilename("${manga.originalTitle()} - Cover.jpg")
|
||||||
|
|
||||||
val destFile = File(directory, filename)
|
val destFile = File(directory, filename)
|
||||||
val stream: OutputStream = FileOutputStream(destFile)
|
val stream: OutputStream = FileOutputStream(destFile)
|
||||||
@ -199,4 +201,71 @@ class MangaInfoPresenter(
|
|||||||
moveMangaToCategories(manga, listOfNotNull(category))
|
moveMangaToCategories(manga, listOfNotNull(category))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateManga(title:String?, author:String?, artist: String?, uri: Uri?,
|
||||||
|
description: String?, tags: Array<String>?) {
|
||||||
|
var changed = false
|
||||||
|
if (title.isNullOrBlank() && manga.currentTitle() != manga.originalTitle()) {
|
||||||
|
manga.title = manga.originalTitle()
|
||||||
|
changed = true
|
||||||
|
} else if (!title.isNullOrBlank() && title != manga.currentTitle()) {
|
||||||
|
manga.title = "${title}${SManga.splitter}${manga.originalTitle()}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (author.isNullOrBlank() && manga.currentAuthor() != manga.originalAuthor()) {
|
||||||
|
manga.author = manga.originalAuthor()
|
||||||
|
changed = true
|
||||||
|
} else if (!author.isNullOrBlank() && author != manga.currentAuthor()) {
|
||||||
|
manga.author = "${author}${SManga.splitter}${manga.originalAuthor()}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (artist.isNullOrBlank() && manga.currentArtist() != manga.currentArtist()) {
|
||||||
|
manga.artist = manga.originalArtist()
|
||||||
|
changed = true
|
||||||
|
} else if (!artist.isNullOrBlank() && artist != manga.currentArtist()) {
|
||||||
|
manga.artist = "${artist}${SManga.splitter}${manga.originalArtist()}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (description.isNullOrBlank() && manga.currentDesc() != manga.originalDesc()) {
|
||||||
|
manga.description = manga.originalDesc()
|
||||||
|
changed = true
|
||||||
|
} else if (!description.isNullOrBlank() && description != manga.currentDesc()) {
|
||||||
|
manga.description = "${description}${SManga.splitter}${manga.originalDesc()}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagsString = tags?.joinToString(", ")
|
||||||
|
if (tagsString.isNullOrBlank() && manga.currentGenres() != manga.originalGenres()) {
|
||||||
|
manga.genre = manga.originalGenres()
|
||||||
|
changed = true
|
||||||
|
} else if (!tagsString.isNullOrBlank() && tagsString != manga.currentGenres()) {
|
||||||
|
tagsString = tags?.joinToString(", ") { it.capitalize() }
|
||||||
|
manga.genre = "${tagsString}${SManga.splitter}${manga.originalGenres()}"
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uri != null) editCoverWithStream(uri)
|
||||||
|
|
||||||
|
|
||||||
|
if (changed) db.updateMangaInfo(manga).executeAsBlocking()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun editCoverWithStream(uri: Uri): Boolean {
|
||||||
|
val inputStream = downloadManager.context.contentResolver.openInputStream(uri) ?:
|
||||||
|
return false
|
||||||
|
if (manga.source == LocalSource.ID) {
|
||||||
|
LocalSource.updateCover(downloadManager.context, manga, inputStream)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (manga.thumbnail_url != null && manga.favorite) {
|
||||||
|
coverCache.copyToCache(manga.thumbnail_url!!, inputStream)
|
||||||
|
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ class TrackSearchDialog : DialogController {
|
|||||||
|
|
||||||
// Do an initial search based on the manga's title
|
// Do an initial search based on the manga's title
|
||||||
if (savedState == null) {
|
if (savedState == null) {
|
||||||
val title = trackController.presenter.manga.trueTitle()
|
val title = trackController.presenter.manga.originalTitle()
|
||||||
view.track_search.append(title)
|
view.track_search.append(title)
|
||||||
search(title)
|
search(title)
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ class MangaHolder(
|
|||||||
|
|
||||||
fun bind(item: MangaItem) {
|
fun bind(item: MangaItem) {
|
||||||
// Update the title of the manga.
|
// Update the title of the manga.
|
||||||
title.text = item.manga.customTitle()
|
title.text = item.manga.currentTitle()
|
||||||
|
|
||||||
// Create thumbnail onclick to simulate long click
|
// Create thumbnail onclick to simulate long click
|
||||||
thumbnail.setOnClickListener {
|
thumbnail.setOnClickListener {
|
||||||
|
@ -23,7 +23,7 @@ import uy.kohesive.injekt.injectLazy
|
|||||||
|
|
||||||
class SearchController(
|
class SearchController(
|
||||||
private var manga: Manga? = null
|
private var manga: Manga? = null
|
||||||
) : CatalogueSearchController(manga?.trueTitle()) {
|
) : CatalogueSearchController(manga?.originalTitle()) {
|
||||||
|
|
||||||
private var newManga: Manga? = null
|
private var newManga: Manga? = null
|
||||||
private var progress = 1
|
private var progress = 1
|
||||||
|
@ -14,7 +14,6 @@ import androidx.core.graphics.ColorUtils
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
@ -155,7 +154,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
|||||||
smartSearchEngine.smartSearch(source, mangaObj.title)
|
smartSearchEngine.smartSearch(source, mangaObj.title)
|
||||||
} else {*/
|
} else {*/
|
||||||
val searchResult = smartSearchEngine
|
val searchResult = smartSearchEngine
|
||||||
.normalSearch(source, mangaObj.trueTitle())
|
.normalSearch(source, mangaObj.originalTitle())
|
||||||
|
|
||||||
if(searchResult != null) {
|
if(searchResult != null) {
|
||||||
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
||||||
@ -185,7 +184,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
|
|||||||
validSources.forEachIndexed { index, source ->
|
validSources.forEachIndexed { index, source ->
|
||||||
val searchResult = try {
|
val searchResult = try {
|
||||||
val searchResult = smartSearchEngine
|
val searchResult = smartSearchEngine
|
||||||
.normalSearch(source, mangaObj.trueTitle())
|
.normalSearch(source, mangaObj.originalTitle())
|
||||||
|
|
||||||
if (searchResult != null) {
|
if (searchResult != null) {
|
||||||
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
|
||||||
|
@ -132,10 +132,10 @@ class MigrationProcessHolder(
|
|||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(thumbnail)
|
.into(thumbnail)
|
||||||
|
|
||||||
title.text = if (manga.customTitle().isBlank()) {
|
title.text = if (manga.currentTitle().isBlank()) {
|
||||||
view.context.getString(R.string.unknown)
|
view.context.getString(R.string.unknown)
|
||||||
} else {
|
} else {
|
||||||
manga.customTitle()
|
manga.currentTitle()
|
||||||
}
|
}
|
||||||
|
|
||||||
gradient.visible()
|
gradient.visible()
|
||||||
|
@ -381,7 +381,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
|
|||||||
viewer = newViewer
|
viewer = newViewer
|
||||||
viewer_container.addView(newViewer.getView())
|
viewer_container.addView(newViewer.getView())
|
||||||
|
|
||||||
toolbar.title = manga.customTitle()
|
toolbar.title = manga.currentTitle()
|
||||||
|
|
||||||
page_seekbar.isRTL = newViewer is R2LPagerViewer
|
page_seekbar.isRTL = newViewer is R2LPagerViewer
|
||||||
|
|
||||||
|
@ -444,7 +444,7 @@ class ReaderPresenter(
|
|||||||
|
|
||||||
// Build destination file.
|
// Build destination file.
|
||||||
val filename = DiskUtil.buildValidFilename(
|
val filename = DiskUtil.buildValidFilename(
|
||||||
"${manga.customTitle()} - ${chapter.name}".take(225)
|
"${manga.currentTitle()} - ${chapter.name}".take(225)
|
||||||
) + " - ${page.number}.${type.extension}"
|
) + " - ${page.number}.${type.extension}"
|
||||||
|
|
||||||
val destFile = File(directory, filename)
|
val destFile = File(directory, filename)
|
||||||
@ -531,7 +531,7 @@ class ReaderPresenter(
|
|||||||
val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found")
|
val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found")
|
||||||
if (manga.favorite) {
|
if (manga.favorite) {
|
||||||
coverCache.copyToCache(thumbUrl, stream())
|
coverCache.copyToCache(thumbUrl, stream())
|
||||||
(manga as? MangaImpl)?.last_cover_fetch = Date().time
|
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
|
||||||
SetAsCoverResult.Success
|
SetAsCoverResult.Success
|
||||||
} else {
|
} else {
|
||||||
SetAsCoverResult.AddToLibraryFirst
|
SetAsCoverResult.AddToLibraryFirst
|
||||||
|
@ -61,7 +61,7 @@ class RecentChapterHolder(private val view: View, private val adapter: RecentCha
|
|||||||
chapter_title.text = item.chapter.name
|
chapter_title.text = item.chapter.name
|
||||||
|
|
||||||
// Set manga title
|
// Set manga title
|
||||||
manga_title.text = item.manga.customTitle()
|
manga_title.text = item.manga.currentTitle()
|
||||||
|
|
||||||
// Set the correct drawable for dropdown and update the tint to match theme.
|
// Set the correct drawable for dropdown and update the tint to match theme.
|
||||||
chapter_menu_icon.setVectorCompat(R.drawable.ic_more_horiz_black_24dp, view.context.getResourceColor(R.attr.icon_color))
|
chapter_menu_icon.setVectorCompat(R.drawable.ic_more_horiz_black_24dp, view.context.getResourceColor(R.attr.icon_color))
|
||||||
|
@ -61,7 +61,7 @@ class RecentlyReadHolder(
|
|||||||
val (manga, chapter, history) = item
|
val (manga, chapter, history) = item
|
||||||
|
|
||||||
// Set manga title
|
// Set manga title
|
||||||
manga_title.text = manga.customTitle()
|
manga_title.text = manga.currentTitle()
|
||||||
|
|
||||||
// Set source + chapter title
|
// Set source + chapter title
|
||||||
val formattedNumber = adapter.decimalFormat.format(chapter.chapter_number.toDouble())
|
val formattedNumber = adapter.decimalFormat.format(chapter.chapter_number.toDouble())
|
||||||
|
@ -74,7 +74,7 @@ object ChapterRecognition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove manga title from chapter title.
|
// Remove manga title from chapter title.
|
||||||
val nameWithoutManga = name.replace(manga.trueTitle().toLowerCase(), "").trim()
|
val nameWithoutManga = name.replace(manga.originalTitle().toLowerCase(), "").trim()
|
||||||
|
|
||||||
// Check if first value is number after title remove.
|
// Check if first value is number after title remove.
|
||||||
if (updateChapter(withoutManga.find(nameWithoutManga), chapter))
|
if (updateChapter(withoutManga.find(nameWithoutManga), chapter))
|
||||||
|
6
app/src/main/res/drawable/circle_backdrop.xml
Normal file
6
app/src/main/res/drawable/circle_backdrop.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid
|
||||||
|
android:color="?attr/colorPrimary"/>
|
||||||
|
</shape>
|
@ -1,9 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24.0"
|
|
||||||
android:viewportHeight="24.0">
|
|
||||||
<path
|
|
||||||
android:fillColor="#FFFFFFFF"
|
|
||||||
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
|
|
||||||
</vector>
|
|
@ -0,0 +1,7 @@
|
|||||||
|
<vector android:height="24dp"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"
|
||||||
|
android:strokeColor="#000000" android:strokeWidth="0.5"/>
|
||||||
|
</vector>
|
7
app/src/main/res/drawable/image_border_background.xml
Normal file
7
app/src/main/res/drawable/image_border_background.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
<stroke android:width="1dp" android:color="@color/snackbarBackground" />
|
||||||
|
<padding android:left="1dp" android:top="1dp" android:right="1dp"
|
||||||
|
android:bottom="1dp" />
|
||||||
|
</shape>
|
112
app/src/main/res/layout/edit_manga_dialog.xml
Normal file
112
app/src/main/res/layout/edit_manga_dialog.xml
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
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:layout_marginBottom="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/manga_cover"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:layout_height="150dp"
|
||||||
|
android:background="@drawable/image_border_background"
|
||||||
|
android:src="@mipmap/ic_launcher"/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="4dp"
|
||||||
|
android:layout_gravity="end|bottom"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:layout_marginBottom="4dp">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:src="@drawable/ic_edit_outlined_white_24dp"/>
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/manga_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="@string/manga_info_author_label"
|
||||||
|
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="@string/manga_info_artist_label"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/reset_tags"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/reset_tags" />
|
||||||
|
|
||||||
|
<me.gujun.android.taggroup.TagGroup
|
||||||
|
android:id="@+id/manga_genres_tags"
|
||||||
|
style="@style/TagGroup"
|
||||||
|
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"
|
||||||
|
app:atg_borderStrokeWidth="1dp"
|
||||||
|
app:atg_backgroundColor="@android:color/transparent"
|
||||||
|
app:atg_isAppendMode="true"
|
||||||
|
app:atg_inputHintColor="?android:attr/textColorSecondary"
|
||||||
|
app:atg_inputTextColor="?android:attr/textColorPrimary"
|
||||||
|
app:atg_checkedBackgroundColor="@color/red_error"
|
||||||
|
app:atg_checkedBorderColor="@color/red_error"
|
||||||
|
app:atg_borderColor="@color/md_blue_A400"
|
||||||
|
app:atg_textColor="@color/md_blue_A400" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/manga_description"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:hint="@string/description"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:inputType="text|textMultiLine"
|
||||||
|
android:scrollHorizontally="false"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?android:attr/divider"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<item android:id="@+id/action_edit"
|
<item android:id="@+id/action_edit"
|
||||||
android:title="@string/action_edit"
|
android:title="@string/action_edit"
|
||||||
android:icon="@drawable/ic_create_white_24dp"
|
android:icon="@drawable/ic_edit_white_24dp"
|
||||||
app:showAsAction="ifRoom"/>
|
app:showAsAction="ifRoom"/>
|
||||||
|
|
||||||
<item android:id="@+id/action_delete"
|
<item android:id="@+id/action_delete"
|
||||||
|
@ -3,11 +3,6 @@
|
|||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<item android:id="@+id/action_edit_cover"
|
|
||||||
android:title="@string/action_edit_cover"
|
|
||||||
android:icon="@drawable/ic_create_white_24dp"
|
|
||||||
app:showAsAction="ifRoom"/>
|
|
||||||
|
|
||||||
<item android:id="@+id/action_move_to_category"
|
<item android:id="@+id/action_move_to_category"
|
||||||
android:title="@string/action_move_category"
|
android:title="@string/action_move_category"
|
||||||
android:icon="@drawable/ic_label_white_24dp"
|
android:icon="@drawable/ic_label_white_24dp"
|
||||||
|
@ -644,5 +644,6 @@
|
|||||||
<string name="use_first_source">Use first source with alternative</string>
|
<string name="use_first_source">Use first source with alternative</string>
|
||||||
<string name="skip_this_step_next_time">Skip this step next time</string>
|
<string name="skip_this_step_next_time">Skip this step next time</string>
|
||||||
<string name="pre_migration_skip_toast">To show this screen again, go to Settings -> Library.</string>
|
<string name="pre_migration_skip_toast">To show this screen again, go to Settings -> Library.</string>
|
||||||
|
<string name="reset_tags">Reset Tags</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user