diff --git a/app/build.gradle b/app/build.gradle index e5fc8aadc2..6dd589c320 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/serializer/MangaTypeAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/serializer/MangaTypeAdapter.kt index cc7d2c068a..e1f7634916 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/serializer/MangaTypeAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/serializer/MangaTypeAdapter.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt index 186928ebf1..0e6d0efb57 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt @@ -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 = mutableMapOf() + + fun setLastCoverFetch(id: Long, time: Long) { + lastCoverFetch[id] = time + } + + fun getLastCoverFetch(id: Long) = lastCoverFetch[id] ?: 0 + } + } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt index 0da34ffe0d..22d21cafc4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt @@ -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) = db.delete().objects(mangas).prepare() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaInfoPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaInfoPutResolver.kt new file mode 100644 index 0000000000..84afbd8139 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaInfoPutResolver.kt @@ -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() { + + 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()) + } + + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt index 0a1e267c4d..9c1886dfe9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadNotifier.kt @@ -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)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt index 1297116ba0..f62a765952 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadProvider.kt @@ -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()) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt index 87ee8cd52a..d53cb5c90a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateRanker.kt @@ -36,7 +36,7 @@ object LibraryUpdateRanker { fun lexicographicRanking(): Comparator { return Comparator { mangaFirst: Manga, mangaSecond: Manga -> - compareValues(mangaFirst.customTitle(), mangaSecond.customTitle()) + compareValues(mangaFirst.currentTitle(), mangaSecond.currentTitle()) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt index 691b2bc162..c814712384 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateService.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/smartsearch/SmartSearchEngine.kt b/app/src/main/java/eu/kanade/tachiyomi/smartsearch/SmartSearchEngine.kt index 16017686f9..4a50f30817 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/smartsearch/SmartSearchEngine.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/smartsearch/SmartSearchEngine.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt index d36da48dfe..90b06d86e6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/LocalSource.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt index 88e0ec0c1c..7630040de9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/source/model/SManga.kt @@ -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() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/BrowseCataloguePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/BrowseCataloguePresenter.kt index c19fa806dd..c43e0082ac 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/BrowseCataloguePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/BrowseCataloguePresenter.kt @@ -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() } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueGridHolder.kt index 1d69853b29..0fb957f2cc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueGridHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueGridHolder.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueListHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueListHolder.kt index 08799d6406..da868dd269 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueListHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/browse/CatalogueListHolder.kt @@ -31,7 +31,7 @@ class CatalogueListHolder(private val view: View, adapter: FlexibleAdapter { - 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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index ffdede61bb..3e0eeb69b8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -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 { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt index 2ee3ade466..49bf5f54c5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryGridHolder.kt @@ -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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt index 6b7a355d51..84999bcdcb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryItem.kt @@ -71,13 +71,14 @@ class LibraryItem(val manga: LibraryManga, private val libraryAsList: Preference val sourceManager by injectLazy() 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") diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt index 79598bface..09beb1e819 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryListHolder.kt @@ -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() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index e9b98f46e6..c078a6101f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -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 - } - } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index d448ef2881..1e736621eb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -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) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/EditMangaDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/EditMangaDialog.kt index 3bb4500947..bb58f6375f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/EditMangaDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/EditMangaDialog.kt @@ -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) { - 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 { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt index ddfc2c3b18..d0b78060e2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoController.kt @@ -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(), 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(), 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(), 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(), // 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() { override fun onResourceReady(resource: Drawable, @@ -336,7 +341,7 @@ class MangaInfoController : NucleusController(), 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(), } 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(), 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(), // 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(), } } + 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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt index 702c65055c..1a79d6b85d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt @@ -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?) { + 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 + } + } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt index 97dce5cc83..469a1fd7de 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/track/TrackSearchDialog.kt @@ -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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaHolder.kt index b7ff6320b3..61a9a14199 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/MangaHolder.kt @@ -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 { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt index b7b8766b82..dd1dc42a40 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/SearchController.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt index ce45681b69..519bee6352 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationListController.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt index 487e247af9..da488c1867 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/migration/manga/process/MigrationProcessHolder.kt @@ -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() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 7e3a64f2e3..a84b986d84 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -381,7 +381,7 @@ class ReaderActivity : BaseRxActivity(), viewer = newViewer viewer_container.addView(newViewer.getView()) - toolbar.title = manga.customTitle() + toolbar.title = manga.currentTitle() page_seekbar.isRTL = newViewer is R2LPagerViewer diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index 375124055a..5dc85411f0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt index cb35f5d4f8..ccc5f22d21 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent_updates/RecentChapterHolder.kt @@ -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)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt index b115e4c167..cd664dff83 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recently_read/RecentlyReadHolder.kt @@ -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()) diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt b/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt index 7fbc0347cb..8294589fb5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/ChapterRecognition.kt @@ -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)) diff --git a/app/src/main/res/drawable/circle_backdrop.xml b/app/src/main/res/drawable/circle_backdrop.xml new file mode 100644 index 0000000000..c6ea3cb6ce --- /dev/null +++ b/app/src/main/res/drawable/circle_backdrop.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_create_white_24dp.xml b/app/src/main/res/drawable/ic_create_white_24dp.xml deleted file mode 100644 index 35a774a517..0000000000 --- a/app/src/main/res/drawable/ic_create_white_24dp.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_edit_outlined_white_24dp.xml b/app/src/main/res/drawable/ic_edit_outlined_white_24dp.xml new file mode 100644 index 0000000000..1090982e08 --- /dev/null +++ b/app/src/main/res/drawable/ic_edit_outlined_white_24dp.xml @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/image_border_background.xml b/app/src/main/res/drawable/image_border_background.xml new file mode 100644 index 0000000000..3bd493d4a1 --- /dev/null +++ b/app/src/main/res/drawable/image_border_background.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/edit_manga_dialog.xml b/app/src/main/res/layout/edit_manga_dialog.xml new file mode 100644 index 0000000000..e1cfd70a36 --- /dev/null +++ b/app/src/main/res/layout/edit_manga_dialog.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + +