UI/Functionality for custom info done

Local Manga is up next
This commit is contained in:
Jay 2020-01-20 01:04:36 -08:00
parent a94d455e79
commit c92b2bb203
44 changed files with 530 additions and 294 deletions

View File

@ -211,7 +211,7 @@ dependencies {
implementation 'me.zhanghai.android.systemuihelper:library:1.0.0'
implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0'
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.carlosesco:DirectionalViewPager:a844dbca0a'

View File

@ -14,7 +14,7 @@ object MangaTypeAdapter {
write {
beginArray()
value(it.url)
value(it.trueTitle())
value(it.originalTitle())
value(it.source)
value(it.viewer)
value(it.chapter_flags)

View File

@ -36,15 +36,12 @@ open class MangaImpl : Manga {
override var hide_title: Boolean = false
var last_cover_fetch: Long = 0
override fun copyFrom(other: SManga) {
if (((other is MangaImpl && (other as MangaImpl)::title.isInitialized)
|| other !is MangaImpl) && other.title != title) {
title = if (customTitle() != trueTitle()) {
val customTitle = customTitle()
if ((other is MangaImpl && (other as MangaImpl)::title.isInitialized && other.title != title)) {
title = if (currentTitle() != originalTitle()) {
val customTitle = currentTitle()
val trueTitle = other.title
"${customTitle}≡§${trueTitle}"
"${customTitle}${SManga.splitter}${trueTitle}"
} else other.title
}
super.copyFrom(other)
@ -64,4 +61,14 @@ open class MangaImpl : Manga {
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
}
}

View File

@ -92,6 +92,16 @@ interface MangaQueries : DbProvider {
.withPutResolver(MangaTitlePutResolver())
.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 deleteMangas(mangas: List<Manga>) = db.delete().objects(mangas).prepare()

View File

@ -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())
}
}

View File

@ -106,7 +106,7 @@ internal class DownloadNotifier(private val context: Context) {
NotificationReceiver.pauseDownloadsPendingBroadcast(context))
}
val title = download.manga.customTitle().chop(15)
val title = download.manga.currentTitle().chop(15)
val quotedTitle = Pattern.quote(title)
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
setContentTitle("$title - $chapter".chop(30))
@ -161,7 +161,7 @@ internal class DownloadNotifier(private val context: Context) {
}
// Create notification.
with(notification) {
val title = download.manga.customTitle().chop(15)
val title = download.manga.currentTitle().chop(15)
val quotedTitle = Pattern.quote(title)
val chapter = download.chapter.name.replaceFirst("$quotedTitle[\\s]*[-]*[\\s]*".toRegex(RegexOption.IGNORE_CASE), "")
setContentTitle("$title - $chapter".chop(30))

View File

@ -178,7 +178,7 @@ class DownloadProvider(private val context: Context) {
* @param manga the manga to query.
*/
fun getMangaDirName(manga: Manga): String {
return DiskUtil.buildValidFilename(manga.trueTitle())
return DiskUtil.buildValidFilename(manga.originalTitle())
}
/**

View File

@ -36,7 +36,7 @@ object LibraryUpdateRanker {
fun lexicographicRanking(): Comparator<Manga> {
return Comparator { mangaFirst: Manga,
mangaSecond: Manga ->
compareValues(mangaFirst.customTitle(), mangaSecond.customTitle())
compareValues(mangaFirst.currentTitle(), mangaSecond.currentTitle())
}
}

View File

@ -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.LibraryManga
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.DownloadService
import eu.kanade.tachiyomi.data.glide.GlideApp
@ -406,7 +407,7 @@ class LibraryUpdateService(
manga.copyFrom(networkManga)
db.insertManga(manga).executeAsBlocking()
coverCache.deleteFromCache(manga.thumbnail_url)
manga.last_cover_fetch = Date().time
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
manga
}
.onErrorReturn { manga }
@ -461,7 +462,7 @@ class LibraryUpdateService(
*/
private fun showProgressNotification(manga: Manga, current: Int, total: Int) {
notificationManager.notify(Notifications.ID_LIBRARY_PROGRESS, progressNotification
.setContentTitle(manga.customTitle())
.setContentTitle(manga.currentTitle())
.setProgress(total, current, false)
.build())
}
@ -487,7 +488,7 @@ class LibraryUpdateService(
}
catch (e: Exception) { }
setGroupAlertBehavior(GROUP_ALERT_SUMMARY)
setContentTitle(manga.customTitle())
setContentTitle(manga.currentTitle())
color = ContextCompat.getColor(this@LibraryUpdateService, R.color.colorAccentLight)
val chaptersNames = if (chapterNames.size > 5) {
"${chapterNames.take(4).joinToString(", ")}, " +
@ -527,11 +528,11 @@ class LibraryUpdateService(
.notification_new_chapters_text,
updates.size, updates.size))
setStyle(NotificationCompat.BigTextStyle().bigText(updates.joinToString("\n") {
it.first.customTitle().chop(45)
it.first.currentTitle().chop(45)
}))
}
else {
setContentText(updates.first().first.customTitle().chop(45))
setContentText(updates.first().first.currentTitle().chop(45))
}
priority = NotificationCompat.PRIORITY_HIGH
setGroup(Notifications.GROUP_NEW_CHAPTERS)

View File

@ -11,7 +11,6 @@ import info.debatty.java.stringsimilarity.NormalizedLevenshtein
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.supervisorScope
import rx.schedulers.Schedulers
import uy.kohesive.injekt.injectLazy
@ -65,7 +64,7 @@ class SmartSearchEngine(parentContext: CoroutineContext,
return@supervisorScope listOf(SearchEntry(searchResults.mangas.first(), 0.0))
searchResults.mangas.map {
val normalizedDistance = normalizedLevenshtein.similarity(title, it.trueTitle())
val normalizedDistance = normalizedLevenshtein.similarity(title, it.originalTitle())
SearchEntry(it, normalizedDistance)
}.filter { (_, normalizedDistance) ->
normalizedDistance >= MIN_NORMAL_ELIGIBLE_THRESHOLD

View File

@ -161,7 +161,7 @@ class LocalSource(private val context: Context) : CatalogueSource {
} else {
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
date_upload = chapterFile.lastModified()
ChapterRecognition.parseChapterNumber(this, manga)

View File

@ -22,28 +22,84 @@ interface SManga : Serializable {
var initialized: Boolean
fun customTitle(): String {
val splitTitle = title.split("")
fun currentTitle(): String {
val splitTitle = title.split(splitter)
return splitTitle.first()
}
fun trueTitle(): String {
val splitTitle = title.split("")
fun originalTitle(): String {
val splitTitle = title.split(splitter)
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) {
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)
artist = other.artist
artist = if (currentArtist() != originalArtist()) {
val current = currentArtist()
val og = other.artist
"${current}$splitter${og}"
} else other.artist
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)
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)
thumbnail_url = other.thumbnail_url
@ -59,6 +115,7 @@ interface SManga : Serializable {
const val ONGOING = 1
const val COMPLETED = 2
const val LICENSED = 3
const val splitter = "▒ ▒∩▒"
fun create(): SManga {
return SMangaImpl()

View File

@ -261,6 +261,7 @@ open class BrowseCataloguePresenter(
coverCache.deleteFromCache(manga.thumbnail_url)
val downloadManager: DownloadManager = Injekt.get()
downloadManager.deleteManga(manga,source)
db.resetMangaInfo(manga).executeAsBlocking()
}
/**

View File

@ -29,7 +29,7 @@ class CatalogueGridHolder(private val view: View, private val adapter: FlexibleA
*/
override fun onSetValues(manga: Manga) {
// Set manga title
title.text = manga.title
title.text = manga.originalTitle()
// Set alpha of thumbnail.
thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f

View File

@ -31,7 +31,7 @@ class CatalogueListHolder(private val view: View, adapter: FlexibleAdapter<IFlex
* @param manga the manga to bind.
*/
override fun onSetValues(manga: Manga) {
title.text = manga.title
title.text = manga.originalTitle()
title.setTextColor(if (manga.favorite) favoriteColor else unfavoriteColor)
setImage(manga)

View File

@ -38,7 +38,7 @@ class DownloadHolder(private val view: View, val adapter: DownloadAdapter) :
chapter_title.text = download.chapter.name
// 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
val pages = download.pages

View File

@ -1,25 +1,15 @@
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.items.IFlexible
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.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.category.CategoryAdapter
import eu.kanade.tachiyomi.util.getResourceColor
import eu.kanade.tachiyomi.util.removeArticles
import uy.kohesive.injekt.injectLazy
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.Year
import java.util.*
@ -94,7 +84,7 @@ class LibraryCategoryAdapter(val view: LibraryCategoryView) :
"N/A"
}
else -> {
val title = (iFlexible as LibraryItem).manga.customTitle()
val title = (iFlexible as LibraryItem).manga.currentTitle()
if (preferences.removeArticles().getOrDefault())
title.removeArticles().substring(0, 1).toUpperCase(Locale.US)
else title.substring(0, 1).toUpperCase(Locale.US)

View File

@ -1,11 +1,8 @@
package eu.kanade.tachiyomi.ui.library
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
@ -18,7 +15,6 @@ import android.view.inputmethod.InputMethodManager
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.SearchView
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.GravityCompat
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.marginTop
import eu.kanade.tachiyomi.util.snack
import eu.kanade.tachiyomi.util.toast
import eu.kanade.tachiyomi.util.updatePaddingRelative
import kotlinx.android.synthetic.main.library_controller.*
import kotlinx.android.synthetic.main.main_activity.*
import rx.Subscription
import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
class LibraryController(
bundle: Bundle? = null,
@ -522,7 +515,6 @@ class LibraryController(
destroyActionModeIfNeeded()
} else {
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 =
!preferences.libraryAsList().getOrDefault()
if (!preferences.libraryAsList().getOrDefault()) {
@ -544,10 +536,6 @@ class LibraryController(
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_edit_cover -> {
changeSelectedCover()
destroyActionModeIfNeeded()
}
R.id.action_move_to_category -> showChangeMangaCategoriesDialog()
R.id.action_delete -> deleteMangasFromLibrary()
R.id.action_select_all -> {
@ -672,55 +660,6 @@ class LibraryController(
presenter.moveMangasToCategories(categories, mangas)
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 {

View File

@ -6,9 +6,11 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.ObjectKey
import eu.davidea.flexibleadapter.FlexibleAdapter
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.source.LocalSource
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.
@ -35,7 +37,7 @@ class LibraryGridHolder(
// Update the title of the manga.
with(title) {
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
@ -57,7 +59,7 @@ class LibraryGridHolder(
GlideApp.with(view.context)
.load(item.manga)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.signature(ObjectKey(item.manga.last_cover_fetch.toString()))
.signature(ObjectKey(MangaImpl.getLastCoverFetch(item.manga.id!!).toString()))
.centerCrop()
.into(thumbnail)
}

View File

@ -71,13 +71,14 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference
val sourceManager by injectLazy<SourceManager>()
val sourceName = sourceManager.getOrStub(manga.source).name
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) ||
if (constraint.contains(",")) {
val genres = manga.genre?.split(", ")
val genres = manga.currentGenres()?.split(", ")
constraint.split(",").all { containsGenre(it.trim(), genres) }
}
else containsGenre(constraint, manga.genre?.split(", "))
else containsGenre(constraint, manga.currentGenres()?.split(", "))
}
@SuppressLint("DefaultLocale")

View File

@ -9,6 +9,7 @@ import kotlinx.android.synthetic.main.catalogue_list_item.*
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.signature.ObjectKey
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.
@ -33,7 +34,7 @@ class LibraryListHolder(
*/
override fun onSetValues(item: LibraryItem) {
// Update the title of the manga.
title.text = item.manga.customTitle()
title.text = item.manga.currentTitle()
// Update the unread count and its visibility.
with(unread_text) {
@ -59,7 +60,7 @@ class LibraryListHolder(
GlideApp.with(itemView.context)
.load(item.manga)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.signature(ObjectKey(item.manga.last_cover_fetch.toString()))
.signature(ObjectKey(MangaImpl.getLastCoverFetch(item.manga.id!!).toString()))
.centerCrop()
.circleCrop()
.dontAnimate()

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.ui.library
import android.os.Bundle
import com.jakewharton.rxrelay.BehaviorRelay
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Category
@ -280,8 +279,8 @@ class LibraryPresenter(
private fun sortAlphabetical(i1: LibraryItem, i2: LibraryItem): Int {
return if (preferences.removeArticles().getOrDefault())
i1.manga.customTitle().removeArticles().compareTo(i2.manga.customTitle().removeArticles(), true)
else i1.manga.customTitle().compareTo(i2.manga.customTitle(), true)
i1.manga.currentTitle().removeArticles().compareTo(i2.manga.currentTitle().removeArticles(), true)
else i1.manga.currentTitle().compareTo(i2.manga.currentTitle(), true)
}
/**
@ -385,6 +384,7 @@ class LibraryPresenter(
Observable.fromCallable {
val mangaToDelete = mangas.distinctBy { it.id }
mangaToDelete.forEach { manga ->
db.resetMangaInfo(manga).executeAsBlocking()
coverCache.deleteFromCache(manga.thumbnail_url)
val source = sourceManager.get(manga.source) as? HttpSource
if (source != null)
@ -503,27 +503,4 @@ class LibraryPresenter(
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
}
}

View File

@ -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.requestPermissionsSafe
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.manga.chapter.ChaptersController
import eu.kanade.tachiyomi.ui.manga.info.MangaInfoController
@ -116,7 +115,7 @@ class MangaController : RxController, TabbedController {
private var trackingIconSubscription: Subscription? = null
override fun getTitle(): String? {
return manga?.customTitle()
return manga?.currentTitle()
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
@ -156,6 +155,11 @@ class MangaController : RxController, TabbedController {
else activity?.tabs
}
fun updateTitle(manga: Manga) {
this.manga?.title = manga.title
setTitle()
}
override fun onChangeEnded(handler: ControllerChangeHandler, type: ControllerChangeType) {
super.onChangeEnded(handler, type)
if (manga == null || source == null) {

View File

@ -1,59 +1,53 @@
package eu.kanade.tachiyomi.ui.manga.info
import android.app.Activity
import android.app.Dialog
import android.content.Intent
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.view.WindowManager
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.WhichButton
import com.afollestad.materialdialogs.actions.setActionButtonEnabled
import com.afollestad.materialdialogs.customview.customView
import com.jakewharton.rxbinding.widget.itemClicks
import com.jakewharton.rxbinding.widget.textChanges
import com.bluelinelabs.conductor.Router
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.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.data.database.models.MangaImpl
import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.ui.base.controller.DialogController
import eu.kanade.tachiyomi.ui.manga.track.TrackController
import eu.kanade.tachiyomi.ui.manga.track.TrackSearchAdapter
import eu.kanade.tachiyomi.ui.manga.track.TrackSearchDialog
import eu.kanade.tachiyomi.util.plusAssign
import kotlinx.android.synthetic.main.track_controller.*
import kotlinx.android.synthetic.main.track_search_dialog.view.*
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.subscriptions.CompositeSubscription
import eu.kanade.tachiyomi.ui.library.LibraryController
import eu.kanade.tachiyomi.util.chop
import eu.kanade.tachiyomi.util.toast
import kotlinx.android.synthetic.main.edit_manga_dialog.view.*
import kotlinx.android.synthetic.main.edit_manga_dialog.view.manga_title
import me.gujun.android.taggroup.TagGroup
import timber.log.Timber
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.concurrent.TimeUnit
import java.io.IOException
import java.io.InputStream
class EditMangaDialog : DialogController {
private var dialogView: View? = null
private var adapter: TrackSearchAdapter? = null
private var selectedItem: Track? = null
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
get() = targetController as TrackController
private var wasPreviouslyTracked:Boolean = false
constructor(target: TrackController, manga: Manga, wasTracked:Boolean) : super(Bundle()
constructor(target: MangaInfoController, manga: Manga) : super(Bundle()
.apply {
putLong(KEY_MANGA, manga.id!!)
}) {
wasPreviouslyTracked = wasTracked
targetController = target
this.manga = manga
}
@ -64,101 +58,112 @@ class EditMangaDialog : DialogController {
.executeAsBlocking()!!
}
override fun showDialog(router: Router) {
super.showDialog(router)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
}
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
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)
positiveButton(
if (wasPreviouslyTracked) R.string.action_clear
else R.string.action_track){ onPositiveButtonClick() }
setActionButtonEnabled(WhichButton.POSITIVE, wasPreviouslyTracked)
}
if (subscriptions.isUnsubscribed) {
subscriptions = CompositeSubscription()
positiveButton(R.string.action_save) { onPositiveButtonClick() }
}
dialogView = dialog.view
onViewCreated(dialog.view, savedViewState)
return dialog
}
fun onViewCreated(view: View, savedState: Bundle?) {
// Create adapter
val adapter = TrackSearchAdapter(view.context)
this.adapter = adapter
view.track_search_list.adapter = adapter
GlideApp.with(view.context)
.asDrawable()
.load(manga)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
.dontAnimate()
.into(view.manga_cover)
// Set listeners
selectedItem = null
if (manga.currentTitle() != manga.originalTitle())
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 ->
selectedItem = adapter.getItem(position)
(dialog as? MaterialDialog)?.positiveButton(R.string.action_track)
(dialog as? MaterialDialog)?.setActionButtonEnabled(WhichButton.POSITIVE, true)
if (manga.currentAuthor() != manga.originalAuthor())
view.manga_author.append(manga.currentAuthor())
if (!manga.originalAuthor().isNullOrBlank())
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 (savedState == null) {
val title = trackController.presenter.manga.trueTitle()
view.track_search.append(title)
search(title)
if (manga.currentArtist() != manga.originalArtist())
view.manga_description.append(manga.currentDesc())
if (!manga.originalDesc().isNullOrBlank())
view.manga_description.hint = "${resources?.getString(R.string.description)}: ${manga
.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) {
super.onDestroyView(view)
subscriptions.unsubscribe()
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() {
//trackController.swipe_refresh.isRefreshing = true
//trackController.presenter.registerTracking(selectedItem, service)
infoController.presenter.updateManga(dialogView?.manga_title?.text.toString(),
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 {

View File

@ -70,8 +70,9 @@ import eu.kanade.tachiyomi.util.updateLayoutParams
import eu.kanade.tachiyomi.util.updatePaddingRelative
import jp.wasabeef.glide.transformations.CropSquareTransformation
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.manga_cover
import kotlinx.android.synthetic.main.manga_info_controller.manga_genres_tags
import uy.kohesive.injekt.injectLazy
import java.io.File
import java.text.DateFormat
@ -181,7 +182,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
shortAnimationDuration = resources?.getInteger(android.R.integer.config_shortAnimTime) ?: 0
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)
}
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) {
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 {
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_web_view -> openInWebView()
R.id.action_share -> prepareToShareManga()
@ -262,39 +266,39 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
val view = view ?: return
//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)
} else {
manga.customTitle()
manga.currentTitle()
}
// Update artist TextView.
manga_artist.text = if (manga.artist.isNullOrBlank()) {
manga_artist.text = if (manga.currentArtist().isNullOrBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.artist
manga.currentArtist()
}
// Update author TextView.
manga_author.text = if (manga.author.isNullOrBlank()) {
manga_author.text = if (manga.currentAuthor().isNullOrBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.author
manga.currentAuthor()
}
// If manga source is known update source TextView.
manga_source.text = source?.toString() ?: view.context.getString(R.string.unknown)
// Update genres list
if (manga.genre.isNullOrBlank().not()) {
manga_genres_tags.setTags(manga.genre?.split(", "))
if (manga.currentGenres().isNullOrBlank().not()) {
manga_genres_tags.setTags(manga.currentGenres()?.split(", "))
}
// Update description TextView.
manga_summary.text = if (manga.description.isNullOrBlank()) {
manga_summary.text = if (manga.currentDesc().isNullOrBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.description
manga.currentDesc()
}
// Update status TextView.
@ -307,19 +311,20 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
// Set the favorite drawable to the correct one.
setFavoriteDrawable(manga.favorite)
activity?.invalidateOptionsMenu()
// Set cover if it wasn't already.
if (!manga.thumbnail_url.isNullOrEmpty()) {
GlideApp.with(view.context)
.load(manga)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.signature(ObjectKey((manga as MangaImpl).last_cover_fetch.toString()))
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
//.centerCrop()
.into(manga_cover)
if (manga_cover_full != null) {
GlideApp.with(view.context).asDrawable().load(manga)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.signature(ObjectKey(manga.last_cover_fetch.toString()))
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
.override(CustomTarget.SIZE_ORIGINAL, CustomTarget.SIZE_ORIGINAL)
.into(object : CustomTarget<Drawable>() {
override fun onResourceReady(resource: Drawable,
@ -336,7 +341,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
GlideApp.with(view.context)
.load(manga)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.signature(ObjectKey(manga.last_cover_fetch.toString()))
.signature(ObjectKey(MangaImpl.getLastCoverFetch(manga.id!!).toString()))
.centerCrop()
.into(backdrop)
}
@ -397,7 +402,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
}
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)
}
@ -433,7 +438,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/*"
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
if (stream != null) {
clipData = ClipData.newRawUri(null, stream)
@ -710,11 +715,11 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
// Check if shortcut placement is supported
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
val shortcutInfo = ShortcutInfoCompat.Builder(activity, shortcutId)
.setShortLabel(presenter.manga.customTitle())
.setShortLabel(presenter.manga.currentTitle())
.setIcon(IconCompat.createWithBitmap(icon))
.setIntent(shortcutIntent)
.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() {
if (setUpFullCover) return
val expandedImageView = manga_cover_full ?: return

View File

@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.manga.info
import android.app.Application
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import com.jakewharton.rxrelay.BehaviorRelay
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.MangaImpl
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.source.LocalSource
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.util.DiskUtil
import eu.kanade.tachiyomi.util.ImageUtil
import eu.kanade.tachiyomi.util.isNullOrUnsubscribed
import rx.Observable
import rx.Subscription
@ -24,7 +26,6 @@ import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStream
import java.io.OutputStream
@ -94,7 +95,7 @@ class MangaInfoPresenter(
manga.initialized = true
db.insertManga(manga).executeAsBlocking()
coverCache.deleteFromCache(manga.thumbnail_url)
(manga as? MangaImpl)?.last_cover_fetch = Date().time
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
manga
}
.subscribeOn(Schedulers.io())
@ -119,6 +120,7 @@ class MangaInfoPresenter(
fun confirmDeletion() {
coverCache.deleteFromCache(manga.thumbnail_url)
db.resetMangaInfo(manga).executeAsBlocking()
downloadManager.deleteManga(manga, source)
}
@ -148,7 +150,7 @@ class MangaInfoPresenter(
directory.mkdirs()
// 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 stream: OutputStream = FileOutputStream(destFile)
@ -199,4 +201,71 @@ class MangaInfoPresenter(
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
}
}

View File

@ -95,7 +95,7 @@ class TrackSearchDialog : DialogController {
// Do an initial search based on the manga's title
if (savedState == null) {
val title = trackController.presenter.manga.trueTitle()
val title = trackController.presenter.manga.originalTitle()
view.track_search.append(title)
search(title)
}

View File

@ -16,7 +16,7 @@ class MangaHolder(
fun bind(item: MangaItem) {
// Update the title of the manga.
title.text = item.manga.customTitle()
title.text = item.manga.currentTitle()
// Create thumbnail onclick to simulate long click
thumbnail.setOnClickListener {

View File

@ -23,7 +23,7 @@ import uy.kohesive.injekt.injectLazy
class SearchController(
private var manga: Manga? = null
) : CatalogueSearchController(manga?.trueTitle()) {
) : CatalogueSearchController(manga?.originalTitle()) {
private var newManga: Manga? = null
private var progress = 1

View File

@ -14,7 +14,6 @@ import androidx.core.graphics.ColorUtils
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
import com.afollestad.materialdialogs.MaterialDialog
import com.bluelinelabs.conductor.ControllerChangeHandler
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
@ -155,7 +154,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
smartSearchEngine.smartSearch(source, mangaObj.title)
} else {*/
val searchResult = smartSearchEngine
.normalSearch(source, mangaObj.trueTitle())
.normalSearch(source, mangaObj.originalTitle())
if(searchResult != null) {
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)
@ -185,7 +184,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
validSources.forEachIndexed { index, source ->
val searchResult = try {
val searchResult = smartSearchEngine
.normalSearch(source, mangaObj.trueTitle())
.normalSearch(source, mangaObj.originalTitle())
if (searchResult != null) {
val localManga = smartSearchEngine.networkToLocalManga(searchResult, source.id)

View File

@ -132,10 +132,10 @@ class MigrationProcessHolder(
.centerCrop()
.into(thumbnail)
title.text = if (manga.customTitle().isBlank()) {
title.text = if (manga.currentTitle().isBlank()) {
view.context.getString(R.string.unknown)
} else {
manga.customTitle()
manga.currentTitle()
}
gradient.visible()

View File

@ -381,7 +381,7 @@ class ReaderActivity : BaseRxActivity<ReaderPresenter>(),
viewer = newViewer
viewer_container.addView(newViewer.getView())
toolbar.title = manga.customTitle()
toolbar.title = manga.currentTitle()
page_seekbar.isRTL = newViewer is R2LPagerViewer

View File

@ -444,7 +444,7 @@ class ReaderPresenter(
// Build destination file.
val filename = DiskUtil.buildValidFilename(
"${manga.customTitle()} - ${chapter.name}".take(225)
"${manga.currentTitle()} - ${chapter.name}".take(225)
) + " - ${page.number}.${type.extension}"
val destFile = File(directory, filename)
@ -531,7 +531,7 @@ class ReaderPresenter(
val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found")
if (manga.favorite) {
coverCache.copyToCache(thumbUrl, stream())
(manga as? MangaImpl)?.last_cover_fetch = Date().time
MangaImpl.setLastCoverFetch(manga.id!!, Date().time)
SetAsCoverResult.Success
} else {
SetAsCoverResult.AddToLibraryFirst

View File

@ -61,7 +61,7 @@ class RecentChapterHolder(private val view: View, private val adapter: RecentCha
chapter_title.text = item.chapter.name
// 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.
chapter_menu_icon.setVectorCompat(R.drawable.ic_more_horiz_black_24dp, view.context.getResourceColor(R.attr.icon_color))

View File

@ -61,7 +61,7 @@ class RecentlyReadHolder(
val (manga, chapter, history) = item
// Set manga title
manga_title.text = manga.customTitle()
manga_title.text = manga.currentTitle()
// Set source + chapter title
val formattedNumber = adapter.decimalFormat.format(chapter.chapter_number.toDouble())

View File

@ -74,7 +74,7 @@ object ChapterRecognition {
}
// 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.
if (updateChapter(withoutManga.find(nameWithoutManga), chapter))

View 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>

View File

@ -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>

View File

@ -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>

View 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>

View 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>

View File

@ -5,7 +5,7 @@
<item android:id="@+id/action_edit"
android:title="@string/action_edit"
android:icon="@drawable/ic_create_white_24dp"
android:icon="@drawable/ic_edit_white_24dp"
app:showAsAction="ifRoom"/>
<item android:id="@+id/action_delete"

View File

@ -3,11 +3,6 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
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"
android:title="@string/action_move_category"
android:icon="@drawable/ic_label_white_24dp"

View File

@ -644,5 +644,6 @@
<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="pre_migration_skip_toast">To show this screen again, go to Settings -> Library.</string>
<string name="reset_tags">Reset Tags</string>
</resources>