mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-24 05:38:01 +03:00
Move edit cover to manga info
This commit is contained in:
parent
1f67695713
commit
9f7fda0bc5
7 changed files with 132 additions and 142 deletions
|
@ -1,7 +1,5 @@
|
|||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
|
@ -37,7 +35,6 @@ import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
|
|||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.main.offsetAppbarHeight
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.hasCustomCover
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.gone
|
||||
|
@ -52,7 +49,6 @@ import reactivecircus.flowbinding.android.view.clicks
|
|||
import reactivecircus.flowbinding.appcompat.queryTextChanges
|
||||
import reactivecircus.flowbinding.viewpager.pageSelections
|
||||
import rx.Subscription
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
|
@ -64,7 +60,6 @@ class LibraryController(
|
|||
RootController,
|
||||
TabbedController,
|
||||
ActionMode.Callback,
|
||||
ChangeMangaCoverDialog.Listener,
|
||||
ChangeMangaCategoriesDialog.Listener,
|
||||
DeleteLibraryMangasDialog.Listener {
|
||||
|
||||
|
@ -88,8 +83,6 @@ class LibraryController(
|
|||
*/
|
||||
val selectedMangas = mutableSetOf<Manga>()
|
||||
|
||||
private var selectedCoverManga: Manga? = null
|
||||
|
||||
/**
|
||||
* Relay to notify the UI of selection updates.
|
||||
*/
|
||||
|
@ -468,7 +461,6 @@ class LibraryController(
|
|||
} else {
|
||||
mode.title = count.toString()
|
||||
|
||||
binding.actionToolbar.findItem(R.id.action_edit_cover)?.isVisible = count == 1
|
||||
binding.actionToolbar.findItem(R.id.action_download_unread)?.isVisible = selectedMangas.any { it.source != LocalSource.ID }
|
||||
}
|
||||
return false
|
||||
|
@ -480,7 +472,6 @@ class LibraryController(
|
|||
|
||||
private fun onActionItemClicked(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_edit_cover -> handleChangeCover()
|
||||
R.id.action_move_to_category -> showChangeMangaCategoriesDialog()
|
||||
R.id.action_download_unread -> downloadUnreadChapters()
|
||||
R.id.action_delete -> showDeleteMangaDialog()
|
||||
|
@ -540,23 +531,6 @@ class LibraryController(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleChangeCover() {
|
||||
val manga = selectedMangas.firstOrNull() ?: return
|
||||
|
||||
if (manga.hasCustomCover(coverCache)) {
|
||||
showEditCoverDialog(manga)
|
||||
} else {
|
||||
openMangaCoverPicker(manga)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit custom cover for selected manga.
|
||||
*/
|
||||
private fun showEditCoverDialog(manga: Manga) {
|
||||
ChangeMangaCoverDialog(this, manga).showDialog(router)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the selected manga to a list of categories.
|
||||
*/
|
||||
|
@ -586,31 +560,6 @@ class LibraryController(
|
|||
DeleteLibraryMangasDialog(this, selectedMangas.toList()).showDialog(router)
|
||||
}
|
||||
|
||||
override fun openMangaCoverPicker(manga: Manga) {
|
||||
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)
|
||||
}
|
||||
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
override fun deleteMangaCover(manga: Manga) {
|
||||
presenter.deleteCustomCover(manga)
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
override fun updateCategoriesForMangas(mangas: List<Manga>, categories: List<Category>) {
|
||||
presenter.moveMangasToCategories(categories, mangas)
|
||||
destroyActionModeIfNeeded()
|
||||
|
@ -632,32 +581,4 @@ class LibraryController(
|
|||
selectInverseRelay.call(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_IMAGE_OPEN) {
|
||||
val dataUri = data?.data
|
||||
if (dataUri == null || resultCode != Activity.RESULT_OK) return
|
||||
val activity = activity ?: return
|
||||
val manga = selectedCoverManga ?: return
|
||||
|
||||
selectedCoverManga = null
|
||||
presenter.editCover(manga, activity, dataUri)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSetCoverSuccess() {
|
||||
activity?.toast(R.string.cover_updated)
|
||||
}
|
||||
|
||||
fun onSetCoverError(error: Throwable) {
|
||||
activity?.toast(R.string.notification_cover_update_failed)
|
||||
Timber.e(error)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
/**
|
||||
* Key to change the cover of a manga in [onActivityResult].
|
||||
*/
|
||||
const val REQUEST_IMAGE_OPEN = 101
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
|
@ -11,7 +9,6 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
|||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
|
@ -21,7 +18,6 @@ import eu.kanade.tachiyomi.util.lang.combineLatest
|
|||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
||||
import java.util.Collections
|
||||
import java.util.Comparator
|
||||
import rx.Observable
|
||||
|
@ -374,46 +370,4 @@ class LibraryPresenter(
|
|||
|
||||
db.setMangaCategories(mc, mangas)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cover with local file.
|
||||
*
|
||||
* @param manga the manga edited.
|
||||
* @param context Context.
|
||||
* @param data uri of the cover resource.
|
||||
*/
|
||||
fun editCover(manga: Manga, context: Context, data: Uri) {
|
||||
Observable
|
||||
.fromCallable {
|
||||
context.contentResolver.openInputStream(data)?.use {
|
||||
if (manga.isLocal()) {
|
||||
LocalSource.updateCover(context, manga, it)
|
||||
manga.updateCoverLastModified(db)
|
||||
} else if (manga.favorite) {
|
||||
coverCache.setCustomCoverToCache(manga, it)
|
||||
manga.updateCoverLastModified(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, _ -> view.onSetCoverSuccess() },
|
||||
{ view, e -> view.onSetCoverError(e) }
|
||||
)
|
||||
}
|
||||
|
||||
fun deleteCustomCover(manga: Manga) {
|
||||
Observable
|
||||
.fromCallable {
|
||||
coverCache.deleteCustomCover(manga)
|
||||
manga.updateCoverLastModified(db)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, _ -> view.onSetCoverSuccess() },
|
||||
{ view, e -> view.onSetCoverError(e) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.google.android.material.snackbar.Snackbar
|
|||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
||||
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
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
|
@ -44,6 +45,7 @@ import eu.kanade.tachiyomi.ui.browse.migration.search.SearchController
|
|||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceController
|
||||
import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController
|
||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCoverDialog
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.ui.main.offsetAppbarHeight
|
||||
|
@ -59,6 +61,7 @@ import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
|||
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
||||
import eu.kanade.tachiyomi.ui.recent.updates.UpdatesController
|
||||
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
|
||||
import eu.kanade.tachiyomi.util.hasCustomCover
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.getCoordinates
|
||||
|
@ -81,6 +84,7 @@ class MangaController :
|
|||
ActionMode.Callback,
|
||||
FlexibleAdapter.OnItemClickListener,
|
||||
FlexibleAdapter.OnItemLongClickListener,
|
||||
ChangeMangaCoverDialog.Listener,
|
||||
ChangeMangaCategoriesDialog.Listener,
|
||||
DownloadCustomChaptersDialog.Listener,
|
||||
DeleteChaptersDialog.Listener {
|
||||
|
@ -113,6 +117,7 @@ class MangaController :
|
|||
private val fromSource = args.getBoolean(FROM_SOURCE_EXTRA, false)
|
||||
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
private val coverCache: CoverCache by injectLazy()
|
||||
|
||||
private var mangaInfoAdapter: MangaInfoHeaderAdapter? = null
|
||||
private var chaptersHeaderAdapter: MangaChaptersHeaderAdapter? = null
|
||||
|
@ -310,7 +315,8 @@ class MangaController :
|
|||
// Hide download options for local manga
|
||||
menu.findItem(R.id.download_group).isVisible = !isLocalSource
|
||||
|
||||
// Hide migrate option for non-library manga
|
||||
// Hide edit cover and migrate options for non-library manga
|
||||
menu.findItem(R.id.action_edit_cover).isVisible = presenter.manga.favorite
|
||||
menu.findItem(R.id.action_migrate).isVisible = presenter.manga.favorite
|
||||
}
|
||||
|
||||
|
@ -371,6 +377,7 @@ class MangaController :
|
|||
activity?.invalidateOptionsMenu()
|
||||
}
|
||||
|
||||
R.id.action_edit_cover -> handleChangeCover()
|
||||
R.id.action_migrate -> migrateManga()
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
|
@ -582,22 +589,78 @@ class MangaController :
|
|||
}
|
||||
}
|
||||
|
||||
// Manga info - end
|
||||
private fun handleChangeCover() {
|
||||
val manga = manga ?: return
|
||||
if (manga.hasCustomCover(coverCache)) {
|
||||
showEditCoverDialog(manga)
|
||||
} else {
|
||||
openMangaCoverPicker(manga)
|
||||
}
|
||||
}
|
||||
|
||||
// Chapters list - start
|
||||
/**
|
||||
* Edit custom cover for selected manga.
|
||||
*/
|
||||
private fun showEditCoverDialog(manga: Manga) {
|
||||
ChangeMangaCoverDialog(this, manga).showDialog(router)
|
||||
}
|
||||
|
||||
override fun openMangaCoverPicker(manga: 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)
|
||||
}
|
||||
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
override fun deleteMangaCover(manga: Manga) {
|
||||
presenter.deleteCustomCover(manga)
|
||||
mangaInfoAdapter?.notifyDataSetChanged()
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_IMAGE_OPEN) {
|
||||
val dataUri = data?.data
|
||||
if (dataUri == null || resultCode != Activity.RESULT_OK) return
|
||||
val activity = activity ?: return
|
||||
presenter.editCover(manga!!, activity, dataUri)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSetCoverSuccess() {
|
||||
mangaInfoAdapter?.notifyDataSetChanged()
|
||||
activity?.toast(R.string.cover_updated)
|
||||
}
|
||||
|
||||
fun onSetCoverError(error: Throwable) {
|
||||
activity?.toast(R.string.notification_cover_update_failed)
|
||||
Timber.e(error)
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates source migration for the specific manga.
|
||||
*/
|
||||
private fun migrateManga() {
|
||||
val controller =
|
||||
SearchController(
|
||||
presenter.manga
|
||||
)
|
||||
val controller = SearchController(presenter.manga)
|
||||
controller.targetController = this
|
||||
router.pushController(controller.withFadeTransaction())
|
||||
}
|
||||
|
||||
// Manga info - end
|
||||
|
||||
// Chapters list - start
|
||||
|
||||
fun onNextChapters(chapters: List<ChapterItem>) {
|
||||
// If the list is empty and it hasn't requested previously, fetch chapters from source
|
||||
// We use presenter chapters instead because they are always unfiltered
|
||||
|
@ -943,5 +1006,10 @@ class MangaController :
|
|||
companion object {
|
||||
const val FROM_SOURCE_EXTRA = "from_source"
|
||||
const val MANGA_EXTRA = "manga"
|
||||
|
||||
/**
|
||||
* Key to change the cover of a manga in [onActivityResult].
|
||||
*/
|
||||
const val REQUEST_IMAGE_OPEN = 101
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package eu.kanade.tachiyomi.ui.manga
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
|
@ -11,6 +13,7 @@ import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
|||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
|
@ -21,6 +24,7 @@ import eu.kanade.tachiyomi.util.lang.launchIO
|
|||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import eu.kanade.tachiyomi.util.shouldDownloadNewChapters
|
||||
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
||||
import java.util.Date
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
|
@ -217,6 +221,48 @@ class MangaPresenter(
|
|||
moveMangaToCategories(manga, listOfNotNull(category))
|
||||
}
|
||||
|
||||
/**
|
||||
* Update cover with local file.
|
||||
*
|
||||
* @param manga the manga edited.
|
||||
* @param context Context.
|
||||
* @param data uri of the cover resource.
|
||||
*/
|
||||
fun editCover(manga: Manga, context: Context, data: Uri) {
|
||||
Observable
|
||||
.fromCallable {
|
||||
context.contentResolver.openInputStream(data)?.use {
|
||||
if (manga.isLocal()) {
|
||||
LocalSource.updateCover(context, manga, it)
|
||||
manga.updateCoverLastModified(db)
|
||||
} else if (manga.favorite) {
|
||||
coverCache.setCustomCoverToCache(manga, it)
|
||||
manga.updateCoverLastModified(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, _ -> view.onSetCoverSuccess() },
|
||||
{ view, e -> view.onSetCoverError(e) }
|
||||
)
|
||||
}
|
||||
|
||||
fun deleteCustomCover(manga: Manga) {
|
||||
Observable
|
||||
.fromCallable {
|
||||
coverCache.deleteCustomCover(manga)
|
||||
manga.updateCoverLastModified(db)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, _ -> view.onSetCoverSuccess() },
|
||||
{ view, e -> view.onSetCoverError(e) }
|
||||
)
|
||||
}
|
||||
|
||||
// Manga info - end
|
||||
|
||||
// Chapters list - start
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.data.glide.MangaThumbnail
|
||||
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.databinding.MangaInfoHeaderBinding
|
||||
|
@ -49,6 +50,7 @@ class MangaInfoHeaderAdapter(
|
|||
private lateinit var binding: MangaInfoHeaderBinding
|
||||
|
||||
private var initialLoad: Boolean = true
|
||||
private var currentMangaThumbnail: MangaThumbnail? = null
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
|
||||
binding = MangaInfoHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
|
@ -237,9 +239,10 @@ class MangaInfoHeaderAdapter(
|
|||
// Set the favorite drawable to the correct one.
|
||||
setFavoriteButtonState(manga.favorite)
|
||||
|
||||
// Set cover if it wasn't already.
|
||||
if (binding.mangaCover.drawable == null) {
|
||||
val mangaThumbnail = manga.toMangaThumbnail()
|
||||
// Set cover if changed.
|
||||
val mangaThumbnail = manga.toMangaThumbnail()
|
||||
if (mangaThumbnail != currentMangaThumbnail) {
|
||||
currentMangaThumbnail = mangaThumbnail
|
||||
listOf(binding.mangaCover, binding.backdrop)
|
||||
.forEach {
|
||||
GlideApp.with(view.context)
|
||||
|
|
|
@ -97,6 +97,11 @@
|
|||
</menu>
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_edit_cover"
|
||||
android:title="@string/action_edit_cover"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_migrate"
|
||||
android:title="@string/action_migrate"
|
||||
|
|
|
@ -2,13 +2,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:icon="@drawable/ic_edit_24dp"
|
||||
android:title="@string/action_edit_cover"
|
||||
app:iconTint="?attr/colorOnPrimary"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_move_to_category"
|
||||
android:icon="@drawable/ic_label_24dp"
|
||||
|
|
Loading…
Reference in a new issue