mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
Detect identical mangas when adding to library
Changes from upstream: Option to migrate/copy from dialog (requires manga to be initialized first) Dialog shows up on all places you can add manga (browse source and global) Closes #1207 Co-Authored-By: Felix Kaiser <30923667+foxscore@users.noreply.github.com>
This commit is contained in:
parent
54b7288acd
commit
0f50c30ad1
13 changed files with 286 additions and 59 deletions
|
@ -44,6 +44,21 @@ interface MangaQueries : DbProvider {
|
|||
.withGetResolver(LibraryMangaGetResolver.INSTANCE)
|
||||
.prepare()
|
||||
|
||||
fun getDuplicateLibraryManga(manga: Manga) = db.get()
|
||||
.`object`(Manga::class.java)
|
||||
.withQuery(
|
||||
Query.builder()
|
||||
.table(MangaTable.TABLE)
|
||||
.where("${MangaTable.COL_FAVORITE} = 1 AND LOWER(${MangaTable.COL_TITLE}) = ? AND ${MangaTable.COL_SOURCE} != ?")
|
||||
.whereArgs(
|
||||
manga.title.lowercase(),
|
||||
manga.source,
|
||||
)
|
||||
.limit(1)
|
||||
.build(),
|
||||
)
|
||||
.prepare()
|
||||
|
||||
fun getFavoriteMangas() = db.get()
|
||||
.listOfObjects(Manga::class.java)
|
||||
.withQuery(
|
||||
|
|
|
@ -1367,6 +1367,8 @@ class MangaDetailsController :
|
|||
presenter.preferences,
|
||||
view,
|
||||
activity,
|
||||
presenter.sourceManager,
|
||||
this,
|
||||
onMangaAdded = {
|
||||
updateHeader()
|
||||
showAddedSnack()
|
||||
|
|
|
@ -32,6 +32,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
|||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.SourceNotFoundException
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.toSChapter
|
||||
|
@ -82,6 +83,7 @@ class MangaDetailsPresenter(
|
|||
|
||||
private val customMangaManager: CustomMangaManager by injectLazy()
|
||||
private val mangaShortcutManager: MangaShortcutManager by injectLazy()
|
||||
val sourceManager: SourceManager by injectLazy()
|
||||
|
||||
private val chapterSort = ChapterSort(manga, chapterFilter, preferences)
|
||||
val extension by lazy { (source as? HttpSource)?.getExtension() }
|
||||
|
|
|
@ -61,7 +61,8 @@ class MigrationProcessAdapter(
|
|||
} && items.any { it.manga.migrationStatus == MigrationStatus.MANGA_FOUND }
|
||||
)
|
||||
|
||||
fun mangasSkipped() = (items.count { it.manga.migrationStatus == MigrationStatus.MANGA_NOT_FOUND })
|
||||
fun mangasSkipped() =
|
||||
(items.count { it.manga.migrationStatus == MigrationStatus.MANGA_NOT_FOUND })
|
||||
|
||||
suspend fun performMigrations(copy: Boolean) {
|
||||
withContext(Dispatchers.IO) {
|
||||
|
@ -70,7 +71,8 @@ class MigrationProcessAdapter(
|
|||
val manga = migratingManga.manga
|
||||
if (manga.searchResult.initialized) {
|
||||
val toMangaObj =
|
||||
db.getManga(manga.searchResult.get() ?: return@forEach).executeAsBlocking()
|
||||
db.getManga(manga.searchResult.get() ?: return@forEach)
|
||||
.executeAsBlocking()
|
||||
?: return@forEach
|
||||
val prevManga = manga.manga() ?: return@forEach
|
||||
val source = sourceManager.get(toMangaObj.source) ?: return@forEach
|
||||
|
@ -128,63 +130,82 @@ class MigrationProcessAdapter(
|
|||
) {
|
||||
if (controller.config == null) return
|
||||
val flags = preferences.migrateFlags().get()
|
||||
// Update chapters read
|
||||
if (MigrationFlags.hasChapters(flags)) {
|
||||
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
|
||||
val maxChapterRead =
|
||||
prevMangaChapters.filter { it.read }.maxOfOrNull { it.chapter_number } ?: 0f
|
||||
val dbChapters = db.getChapters(manga).executeAsBlocking()
|
||||
val prevHistoryList = db.getHistoryByMangaId(prevManga.id!!).executeAsBlocking()
|
||||
val historyList = mutableListOf<History>()
|
||||
for (chapter in dbChapters) {
|
||||
if (chapter.isRecognizedNumber) {
|
||||
val prevChapter =
|
||||
prevMangaChapters.find { it.isRecognizedNumber && it.chapter_number == chapter.chapter_number }
|
||||
if (prevChapter != null) {
|
||||
chapter.bookmark = prevChapter.bookmark
|
||||
chapter.read = prevChapter.read
|
||||
chapter.date_fetch = prevChapter.date_fetch
|
||||
prevHistoryList.find { it.chapter_id == prevChapter.id }?.let { prevHistory ->
|
||||
val history = History.create(chapter).apply { last_read = prevHistory.last_read }
|
||||
historyList.add(history)
|
||||
migrateMangaInternal(flags, db, enhancedServices, prevSource, source, prevManga, manga, replace)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun migrateMangaInternal(
|
||||
flags: Int,
|
||||
db: DatabaseHelper,
|
||||
enhancedServices: List<EnhancedTrackService>,
|
||||
prevSource: Source?,
|
||||
source: Source,
|
||||
prevManga: Manga,
|
||||
manga: Manga,
|
||||
replace: Boolean
|
||||
) {
|
||||
// Update chapters read
|
||||
if (MigrationFlags.hasChapters(flags)) {
|
||||
val prevMangaChapters = db.getChapters(prevManga).executeAsBlocking()
|
||||
val maxChapterRead =
|
||||
prevMangaChapters.filter { it.read }.maxOfOrNull { it.chapter_number } ?: 0f
|
||||
val dbChapters = db.getChapters(manga).executeAsBlocking()
|
||||
val prevHistoryList = db.getHistoryByMangaId(prevManga.id!!).executeAsBlocking()
|
||||
val historyList = mutableListOf<History>()
|
||||
for (chapter in dbChapters) {
|
||||
if (chapter.isRecognizedNumber) {
|
||||
val prevChapter =
|
||||
prevMangaChapters.find { it.isRecognizedNumber && it.chapter_number == chapter.chapter_number }
|
||||
if (prevChapter != null) {
|
||||
chapter.bookmark = prevChapter.bookmark
|
||||
chapter.read = prevChapter.read
|
||||
chapter.date_fetch = prevChapter.date_fetch
|
||||
prevHistoryList.find { it.chapter_id == prevChapter.id }
|
||||
?.let { prevHistory ->
|
||||
val history = History.create(chapter)
|
||||
.apply { last_read = prevHistory.last_read }
|
||||
historyList.add(history)
|
||||
}
|
||||
} else if (chapter.chapter_number <= maxChapterRead) {
|
||||
chapter.read = true
|
||||
}
|
||||
} else if (chapter.chapter_number <= maxChapterRead) {
|
||||
chapter.read = true
|
||||
}
|
||||
}
|
||||
db.insertChapters(dbChapters).executeAsBlocking()
|
||||
db.updateHistoryLastRead(historyList).executeAsBlocking()
|
||||
}
|
||||
db.insertChapters(dbChapters).executeAsBlocking()
|
||||
db.updateHistoryLastRead(historyList).executeAsBlocking()
|
||||
}
|
||||
// Update categories
|
||||
if (MigrationFlags.hasCategories(flags)) {
|
||||
val categories = db.getCategoriesForManga(prevManga).executeAsBlocking()
|
||||
val mangaCategories = categories.map { MangaCategory.create(manga, it) }
|
||||
db.setMangaCategories(mangaCategories, listOf(manga))
|
||||
}
|
||||
// Update track
|
||||
if (MigrationFlags.hasTracks(flags)) {
|
||||
val tracksToUpdate = db.getTracks(prevManga).executeAsBlocking().mapNotNull { track ->
|
||||
track.id = null
|
||||
track.manga_id = manga.id!!
|
||||
// Update categories
|
||||
if (MigrationFlags.hasCategories(flags)) {
|
||||
val categories = db.getCategoriesForManga(prevManga).executeAsBlocking()
|
||||
val mangaCategories = categories.map { MangaCategory.create(manga, it) }
|
||||
db.setMangaCategories(mangaCategories, listOf(manga))
|
||||
}
|
||||
// Update track
|
||||
if (MigrationFlags.hasTracks(flags)) {
|
||||
val tracksToUpdate =
|
||||
db.getTracks(prevManga).executeAsBlocking().mapNotNull { track ->
|
||||
track.id = null
|
||||
track.manga_id = manga.id!!
|
||||
|
||||
val service = enhancedServices
|
||||
.firstOrNull { it.isTrackFrom(track, prevManga, prevSource) }
|
||||
if (service != null) service.migrateTrack(track, manga, source)
|
||||
else track
|
||||
val service = enhancedServices
|
||||
.firstOrNull { it.isTrackFrom(track, prevManga, prevSource) }
|
||||
if (service != null) service.migrateTrack(track, manga, source)
|
||||
else track
|
||||
}
|
||||
db.insertTracks(tracksToUpdate).executeAsBlocking()
|
||||
}
|
||||
db.insertTracks(tracksToUpdate).executeAsBlocking()
|
||||
// Update favorite status
|
||||
if (replace) {
|
||||
prevManga.favorite = false
|
||||
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()
|
||||
db.updateMangaAdded(manga).executeAsBlocking()
|
||||
db.updateMangaTitle(manga).executeAsBlocking()
|
||||
}
|
||||
// Update favorite status
|
||||
if (replace) {
|
||||
prevManga.favorite = false
|
||||
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()
|
||||
db.updateMangaAdded(manga).executeAsBlocking()
|
||||
db.updateMangaTitle(manga).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -700,6 +700,8 @@ open class BrowseSourceController(bundle: Bundle) :
|
|||
preferences,
|
||||
view,
|
||||
activity,
|
||||
presenter.sourceManager,
|
||||
this,
|
||||
onMangaAdded = {
|
||||
adapter?.notifyItemChanged(position)
|
||||
snack = view.snack(R.string.added_to_library)
|
||||
|
|
|
@ -53,7 +53,7 @@ import uy.kohesive.injekt.api.get
|
|||
open class BrowseSourcePresenter(
|
||||
private val sourceId: Long,
|
||||
searchQuery: String? = null,
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
val sourceManager: SourceManager = Injekt.get(),
|
||||
val db: DatabaseHelper = Injekt.get(),
|
||||
val prefs: PreferencesHelper = Injekt.get(),
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
|
|
|
@ -123,7 +123,21 @@ open class GlobalSearchController(
|
|||
preferences,
|
||||
view,
|
||||
activity,
|
||||
onMangaAdded = {
|
||||
presenter.sourceManager,
|
||||
this,
|
||||
onMangaAdded = { migrationInfo ->
|
||||
migrationInfo?.let { (source, stillFaved) ->
|
||||
val index = this.adapter
|
||||
?.currentItems?.indexOfFirst { it.source.id == source } ?: return@let
|
||||
val item = this.adapter?.getItem(index) ?: return@let
|
||||
val oldMangaIndex = item.results?.indexOfFirst {
|
||||
it.manga.title.lowercase() == manga.title.lowercase()
|
||||
} ?: return@let
|
||||
val oldMangaItem = item.results.getOrNull(oldMangaIndex)
|
||||
oldMangaItem?.manga?.favorite = stillFaved
|
||||
val holder = binding.recycler.findViewHolderForAdapterPosition(index) as? GlobalSearchHolder
|
||||
holder?.updateManga(oldMangaIndex)
|
||||
}
|
||||
adapter.notifyItemChanged(position)
|
||||
snack = view.snack(R.string.added_to_library)
|
||||
},
|
||||
|
|
|
@ -81,6 +81,8 @@ class GlobalSearchHolder(view: View, val adapter: GlobalSearchAdapter) :
|
|||
}
|
||||
}
|
||||
|
||||
fun updateManga(position: Int) = mangaAdapter.notifyItemChanged(position)
|
||||
|
||||
/**
|
||||
* Called from the presenter when a manga is initialized.
|
||||
*
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
package eu.kanade.tachiyomi.util
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -16,10 +20,18 @@ import eu.kanade.tachiyomi.data.track.TrackService
|
|||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.category.addtolibrary.SetCategoriesSheet
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
||||
import eu.kanade.tachiyomi.ui.migration.MigrationFlags
|
||||
import eu.kanade.tachiyomi.ui.migration.manga.process.MigrationProcessAdapter
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithTrackServiceTwoWay
|
||||
import eu.kanade.tachiyomi.util.lang.asButton
|
||||
import eu.kanade.tachiyomi.util.system.launchIO
|
||||
import eu.kanade.tachiyomi.util.system.materialAlertDialog
|
||||
import eu.kanade.tachiyomi.util.system.setCustomTitleAndMessage
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.system.withUIContext
|
||||
import eu.kanade.tachiyomi.util.view.snack
|
||||
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.widget.TriStateCheckBox
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.Injekt
|
||||
|
@ -104,11 +116,46 @@ fun Manga.addOrRemoveToFavorites(
|
|||
preferences: PreferencesHelper,
|
||||
view: View,
|
||||
activity: Activity,
|
||||
onMangaAdded: () -> Unit,
|
||||
sourceManager: SourceManager,
|
||||
controller: Controller,
|
||||
checkForDupes: Boolean = true,
|
||||
onMangaAdded: (Pair<Long, Boolean>?) -> Unit,
|
||||
onMangaMoved: () -> Unit,
|
||||
onMangaDeleted: () -> Unit
|
||||
onMangaDeleted: () -> Unit,
|
||||
): Snackbar? {
|
||||
if (!favorite) {
|
||||
if (checkForDupes) {
|
||||
val duplicateManga = db.getDuplicateLibraryManga(this).executeAsBlocking()
|
||||
if (duplicateManga != null) {
|
||||
showAddDuplicateDialog(
|
||||
this,
|
||||
duplicateManga,
|
||||
activity,
|
||||
db,
|
||||
sourceManager,
|
||||
controller,
|
||||
addManga = {
|
||||
addOrRemoveToFavorites(
|
||||
db,
|
||||
preferences,
|
||||
view,
|
||||
activity,
|
||||
sourceManager,
|
||||
controller,
|
||||
false,
|
||||
onMangaAdded,
|
||||
onMangaMoved,
|
||||
onMangaDeleted
|
||||
)
|
||||
},
|
||||
migrateManga = { source, faved ->
|
||||
onMangaAdded(source to faved)
|
||||
}
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
val categories = db.getCategories().executeAsBlocking()
|
||||
val defaultCategoryId = preferences.defaultCategory()
|
||||
val defaultCategory = categories.find { it.id == defaultCategoryId }
|
||||
|
@ -155,7 +202,7 @@ fun Manga.addOrRemoveToFavorites(
|
|||
ids,
|
||||
true
|
||||
) {
|
||||
onMangaAdded()
|
||||
onMangaAdded(null)
|
||||
autoAddTrack(db, onMangaMoved)
|
||||
}.show()
|
||||
}
|
||||
|
@ -188,6 +235,102 @@ fun Manga.addOrRemoveToFavorites(
|
|||
return null
|
||||
}
|
||||
|
||||
private fun showAddDuplicateDialog(
|
||||
newManga: Manga,
|
||||
libraryManga: Manga,
|
||||
activity: Activity,
|
||||
db: DatabaseHelper,
|
||||
sourceManager: SourceManager,
|
||||
controller: Controller,
|
||||
addManga: () -> Unit,
|
||||
migrateManga: (Long, Boolean) -> Unit,
|
||||
) {
|
||||
val source = sourceManager.getOrStub(libraryManga.source)
|
||||
|
||||
fun migrateManga(mDialog: DialogInterface, replace: Boolean) {
|
||||
val listView = (mDialog as AlertDialog).listView
|
||||
var flags = 0
|
||||
if (listView.isItemChecked(0)) flags = flags or MigrationFlags.CHAPTERS
|
||||
if (listView.isItemChecked(1)) flags = flags or MigrationFlags.CATEGORIES
|
||||
if (listView.isItemChecked(2)) flags = flags or MigrationFlags.TRACK
|
||||
val enhancedServices by lazy { Injekt.get<TrackManager>().services.filterIsInstance<EnhancedTrackService>() }
|
||||
MigrationProcessAdapter.migrateMangaInternal(
|
||||
flags,
|
||||
db,
|
||||
enhancedServices,
|
||||
source,
|
||||
sourceManager.getOrStub(newManga.source),
|
||||
libraryManga,
|
||||
newManga,
|
||||
replace
|
||||
)
|
||||
migrateManga(libraryManga.source, !replace)
|
||||
}
|
||||
|
||||
activity.materialAlertDialog().apply {
|
||||
setCustomTitleAndMessage(0, activity.getString(R.string.confirm_manga_add_duplicate, source.name))
|
||||
setItems(
|
||||
arrayOf(
|
||||
activity.getString(R.string.show_, libraryManga.seriesType(activity, sourceManager)).asButton(activity),
|
||||
activity.getString(R.string.add_to_library).asButton(activity),
|
||||
activity.getString(R.string.migrate).asButton(activity, !newManga.initialized),
|
||||
)
|
||||
) { dialog, i ->
|
||||
when (i) {
|
||||
0 -> controller.router.pushController(
|
||||
MangaDetailsController(libraryManga)
|
||||
.withFadeTransaction()
|
||||
)
|
||||
1 -> addManga()
|
||||
2 -> {
|
||||
if (!newManga.initialized) {
|
||||
activity.toast(R.string.must_view_details_before_migration, Toast.LENGTH_LONG)
|
||||
return@setItems
|
||||
}
|
||||
activity.materialAlertDialog().apply {
|
||||
setTitle(R.string.migration)
|
||||
setMultiChoiceItems(
|
||||
arrayOf(
|
||||
activity.getString(R.string.chapters),
|
||||
activity.getString(R.string.categories),
|
||||
activity.getString(R.string.tracking),
|
||||
),
|
||||
booleanArrayOf(true, true, true), null
|
||||
)
|
||||
setPositiveButton(R.string.migrate) { mDialog, _ ->
|
||||
migrateManga(mDialog, true)
|
||||
}
|
||||
setNegativeButton(R.string.copy) { mDialog, _ ->
|
||||
migrateManga(mDialog, false)
|
||||
}
|
||||
setNeutralButton(android.R.string.cancel, null)
|
||||
setCancelable(true)
|
||||
}.show()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
setNegativeButton(activity.getString(android.R.string.cancel)) { _, _ -> }
|
||||
setCancelable(true)
|
||||
}.create().apply {
|
||||
setOnShowListener {
|
||||
if (!newManga.initialized) {
|
||||
val listView = (it as AlertDialog).listView
|
||||
val view = listView.getChildAt(2)
|
||||
view?.setOnClickListener {
|
||||
if (!newManga.initialized) {
|
||||
activity.toast(
|
||||
R.string.must_view_details_before_migration,
|
||||
Toast.LENGTH_LONG
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
|
||||
fun Manga.autoAddTrack(db: DatabaseHelper, onMangaMoved: () -> Unit) {
|
||||
val loggedServices = Injekt.get<TrackManager>().services.filter { it.isLogged }
|
||||
val source = Injekt.get<SourceManager>().getOrStub(this.source)
|
||||
|
|
|
@ -6,13 +6,18 @@ import android.text.Spannable
|
|||
import android.text.SpannableString
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.SpannedString
|
||||
import android.text.style.BackgroundColorSpan
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.RelativeSizeSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.text.style.SuperscriptSpan
|
||||
import android.text.style.TextAppearanceSpan
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.color
|
||||
import androidx.core.text.inSpans
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import net.greypanther.natsort.CaseInsensitiveSimpleNaturalComparator
|
||||
|
@ -111,6 +116,19 @@ fun String.highlightText(highlight: String, @ColorInt color: Int): Spanned {
|
|||
return wordToSpan
|
||||
}
|
||||
|
||||
fun String.asButton(context: Context, disabled: Boolean = false): SpannedString {
|
||||
return buildSpannedString {
|
||||
val buttonSpan: SpannableStringBuilder.() -> Unit = {
|
||||
inSpans(
|
||||
TextAppearanceSpan(context, R.style.TextAppearance_Tachiyomi_Button)
|
||||
) { append(this@asButton) }
|
||||
}
|
||||
if (disabled) {
|
||||
color(context.getColor(R.color.material_on_surface_disabled), buttonSpan)
|
||||
} else buttonSpan()
|
||||
}
|
||||
}
|
||||
|
||||
fun String.indexesOf(substr: String, ignoreCase: Boolean = true): List<Int> {
|
||||
val list = mutableListOf<Int>()
|
||||
if (substr.isBlank()) return list
|
||||
|
|
|
@ -63,7 +63,11 @@ fun AlertDialog.disableItems(items: Array<String>) {
|
|||
fun MaterialAlertDialogBuilder.setCustomTitleAndMessage(title: Int, message: String): MaterialAlertDialogBuilder {
|
||||
return setCustomTitle(
|
||||
(CustomDialogTitleMessageBinding.inflate(LayoutInflater.from(context))).apply {
|
||||
alertTitle.text = context.getString(title)
|
||||
if (title != 0) {
|
||||
alertTitle.text = context.getString(title)
|
||||
} else {
|
||||
alertTitle.isVisible = false
|
||||
}
|
||||
this.message.text = message
|
||||
}.root
|
||||
)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@android:id/message"
|
||||
android:paddingTop="@dimen/abc_dialog_padding_top_material"
|
||||
android:paddingLeft="?attr/dialogPreferredPadding"
|
||||
android:paddingRight="?attr/dialogPreferredPadding" />
|
||||
|
|
|
@ -504,6 +504,9 @@
|
|||
<string name="added_to_library">Added to library</string>
|
||||
<string name="add_to_library">Add to Library</string>
|
||||
<string name="removed_from_library">Removed from library</string>
|
||||
<string name="show_">Show %1$s</string>
|
||||
<string name="must_view_details_before_migration">This entry\'s details page must be viewed before being able to migrate</string>
|
||||
<string name="confirm_manga_add_duplicate">You have an entry in your library with the same name but from a different source (%1$s).\n\nDo you still wish to continue?</string>
|
||||
<string name="_copied_to_clipboard">%1$s copied to clipboard</string>
|
||||
<string name="source_not_installed_">Source not installed: %1$s</string>
|
||||
<string name="no_description">No description</string>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue