Added option to migrate manga from manga details

Also copying manga date added to migrated manga
This commit is contained in:
Jay 2020-04-12 18:53:56 -04:00
parent 0b0f985e24
commit 3a4780e19b
10 changed files with 112 additions and 35 deletions

View File

@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.data.database.DbProvider
import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaDateAddedPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
import eu.kanade.tachiyomi.data.database.resolvers.MangaInfoPutResolver
@ -92,6 +93,11 @@ interface MangaQueries : DbProvider {
.withPutResolver(MangaFavoritePutResolver())
.prepare()
fun updateMangaAdded(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaDateAddedPutResolver())
.prepare()
fun updateMangaViewer(manga: Manga) = db.put()
.`object`(manga)
.withPutResolver(MangaViewerPutResolver())

View File

@ -0,0 +1,31 @@
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 MangaDateAddedPutResolver : PutResolver<Manga>() {
override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
val updateQuery = mapToUpdateQuery(manga)
val contentValues = 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_DATE_ADDED, manga.date_added)
}
}

View File

@ -52,8 +52,6 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.ui.main.RootSearchInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.getResourceColor
@ -893,15 +891,7 @@ class LibraryController(
}
R.id.action_migrate -> {
val skipPre = preferences.skipPreMigration().getOrDefault()
router.pushController(
if (skipPre) {
MigrationListController.create(
MigrationProcedureConfig(selectedMangas.mapNotNull { it.id }, null)
)
} else {
PreMigrationController.create(selectedMangas.mapNotNull { it.id })
}.withFadeTransaction().tag(if (skipPre) MigrationListController.TAG else null)
)
PreMigrationController.navigateToMigration(skipPre, router, selectedMangas.mapNotNull { it.id })
destroyActionModeIfNeeded()
}
else -> return false

View File

@ -71,6 +71,7 @@ import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.track.model.TrackSearch
import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.Source
@ -89,6 +90,7 @@ import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersSortBottomSheet
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
import eu.kanade.tachiyomi.ui.manga.track.TrackingBottomSheet
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.ui.webview.WebViewActivity
@ -690,10 +692,15 @@ class MangaDetailsController : BaseController,
menu.findItem(R.id.action_mark_all_as_unread).isVisible =
!presenter.allUnread() && !presenter.isLockedFromSearch
menu.findItem(R.id.action_remove_downloads).isVisible =
presenter.hasDownloads() && !presenter.isLockedFromSearch
presenter.hasDownloads() && !presenter.isLockedFromSearch &&
manga?.source != LocalSource.ID
menu.findItem(R.id.remove_non_bookmarked).isVisible =
presenter.hasBookmark() && !presenter.isLockedFromSearch
menu.findItem(R.id.action_mark_all_as_unread).isVisible = presenter.isTracked()
menu.findItem(R.id.action_migrate).isVisible = !presenter.isLockedFromSearch &&
manga?.source != LocalSource.ID && presenter.manga.favorite
menu.findItem(R.id.action_migrate).title = view?.context?.getString(R.string.migrate_,
presenter.manga.mangaType(view!!.context))
val iconPrimary = view?.context?.getResourceColor(android.R.attr.textColorPrimary)
?: Color.BLACK
menu.findItem(R.id.action_download).icon?.mutate()?.setTint(iconPrimary)
@ -753,6 +760,11 @@ class MangaDetailsController : BaseController,
R.id.action_open_in_web_view -> openInWebView()
R.id.action_add_to_home_screen -> addToHomeScreen()
R.id.action_refresh_tracking -> presenter.refreshTrackers()
R.id.action_migrate ->
PreMigrationController.navigateToMigration(
presenter.preferences.skipPreMigration().getOrDefault(),
router,
listOf(manga!!.id!!))
R.id.action_mark_all_as_read -> {
MaterialDialog(view!!.context).message(R.string.mark_all_chapters_as_read)
.positiveButton(R.string.mark_as_read) {

View File

@ -11,10 +11,7 @@ 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.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationListController
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcedureConfig
import eu.kanade.tachiyomi.util.system.await
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
@ -111,10 +108,9 @@ class MigrationController : NucleusController<MigrationPresenter>(),
val item = adapter?.getItem(position) ?: return false
if (item is MangaItem) {
val controller = PreMigrationController.create(listOf(item.manga.id!!))
controller.targetController = this
router.pushController(controller.withFadeTransaction())
PreMigrationController.navigateToMigration(Injekt.get<PreferencesHelper>().skipPreMigration().getOrDefault(),
router,
listOf(item.manga.id!!))
} else if (item is SourceItem) {
presenter.setSelectedSource(item.source)
}
@ -135,15 +131,9 @@ class MigrationController : NucleusController<MigrationPresenter>(),
val sourceMangas =
manga.asSequence().filter { it.source == item.source.id }.map { it.id!! }.toList()
withContext(Dispatchers.Main) {
router.pushController(
if (Injekt.get<PreferencesHelper>().skipPreMigration().getOrDefault()) {
MigrationListController.create(
MigrationProcedureConfig(sourceMangas, null)
)
} else {
PreMigrationController.create(sourceMangas)
}.withFadeTransaction()
)
PreMigrationController.navigateToMigration(Injekt.get<PreferencesHelper>().skipPreMigration().getOrDefault(),
router,
sourceMangas)
}
}
}

View File

@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.recyclerview.widget.LinearLayoutManager
import com.bluelinelabs.conductor.Router
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import eu.davidea.flexibleadapter.FlexibleAdapter
@ -152,6 +153,18 @@ class PreMigrationController(bundle: Bundle? = null) : BaseController(bundle), F
companion object {
private const val MANGA_IDS_EXTRA = "manga_ids"
fun navigateToMigration(skipPre: Boolean, router: Router, mangaIds: List<Long>) {
router.pushController(
if (skipPre) {
MigrationListController.create(
MigrationProcedureConfig(mangaIds, null)
)
} else {
create(mangaIds)
}.withFadeTransaction().tag(if (skipPre) MigrationListController.TAG else null)
)
}
fun create(mangaIds: List<Long>): PreMigrationController {
return PreMigrationController(Bundle().apply {
putLongArray(MANGA_IDS_EXTRA, mangaIds.toLongArray())

View File

@ -14,6 +14,7 @@ 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.changehandler.FadeChangeHandler
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
@ -27,10 +28,13 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.main.BottomNavBarInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.migration.MigrationMangaDialog
import eu.kanade.tachiyomi.ui.migration.SearchController
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
import eu.kanade.tachiyomi.util.system.await
import eu.kanade.tachiyomi.util.system.executeOnIO
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.toast
@ -383,17 +387,40 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
fun migrateMangas() {
launchUI {
adapter?.performMigrations(false)
router.popCurrentController()
navigateOut()
}
}
fun copyMangas() {
launchUI {
adapter?.performMigrations(true)
router.popCurrentController()
navigateOut()
}
}
private fun navigateOut() {
if (migratingManga?.size == 1) {
launchUI {
val hasDetails = router.backstack.any { it.controller() is MangaDetailsController }
if (hasDetails) {
val manga = migratingManga?.firstOrNull()?.searchResult?.get()?.let {
db.getManga(it).executeOnIO()
}
if (manga != null) {
val newStack = router.backstack.filter {
it.controller() !is MangaDetailsController &&
it.controller() !is MigrationListController &&
it.controller() !is PreMigrationController
} + MangaDetailsController(manga).withFadeTransaction()
router.setBackstack(newStack, FadeChangeHandler())
return@launchUI
}
}
router.popCurrentController()
}
} else router.popCurrentController()
}
override fun handleBack(): Boolean {
activity?.let {
MaterialDialog(it).show {

View File

@ -13,6 +13,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.withContext
import uy.kohesive.injekt.injectLazy
import java.util.Date
class MigrationProcessAdapter(
val controller: MigrationListController
@ -101,8 +102,8 @@ class MigrationProcessAdapter(
// Update chapters read
if (MigrationFlags.hasChapters(flags)) {
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
val maxChapterRead = prevMangaChapters.filter { it.read }
.maxBy { it.chapter_number }?.chapter_number
val maxChapterRead =
prevMangaChapters.filter { it.read }.maxBy { it.chapter_number }?.chapter_number
if (maxChapterRead != null) {
val dbChapters = db.getChapters(manga).executeAsBlocking()
for (chapter in dbChapters) {
@ -134,10 +135,10 @@ class MigrationProcessAdapter(
db.updateMangaFavorite(prevManga).executeAsBlocking()
}
manga.favorite = true
if (replace) manga.date_added = prevManga.date_added
else manga.date_added = Date().time
db.updateMangaFavorite(manga).executeAsBlocking()
// SearchPresenter#networkToLocalManga may have updated the manga title, so ensure db gets updated title
db.updateMangaAdded(manga).executeAsBlocking()
db.updateMangaTitle(manga).executeAsBlocking()
// }
}
}

View File

@ -73,6 +73,12 @@
android:title="@string/edit"
app:showAsAction="never" />
<item
android:id="@+id/action_migrate"
android:icon="@drawable/ic_swap_calls_white_24dp"
android:title="@string/migrate"
app:showAsAction="never" />
<item
android:id="@+id/action_add_to_home_screen"
android:title="@string/add_to_home_screen"

View File

@ -402,6 +402,7 @@
<string name="copy_now">Copy now</string>
<string name="select">Select</string>
<string name="migrate">Migrate</string>
<string name="migrate_">Migrate %1$s</string>
<string name="copy_value">Copy</string>
<string name="no_chapters_found_for_migration">No chapters found, this manga cannot be used for
migration</string>