Updates To Snackbar logic
Removed experimnetal coroutines Snackbar for removing mangas now remove downloads when they disappear. Undo Snackbars now disappear when touching somewhere thats not them Opening Tachiyomi from a url (ie mangadex) now automatically goes to the manga page once the search finishes Fixed self made typo in "Update Library" Removed Delete Mangas dialog as it is unused
This commit is contained in:
parent
ae5ad2a9a6
commit
72e7b649a2
@ -258,12 +258,6 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin {
|
|
||||||
experimental {
|
|
||||||
coroutines 'enable'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
androidExtensions {
|
androidExtensions {
|
||||||
experimental = true
|
experimental = true
|
||||||
}
|
}
|
||||||
|
@ -67,25 +67,4 @@ class CoverCache(private val context: Context) {
|
|||||||
val file = getCoverFile(thumbnailUrl)
|
val file = getCoverFile(thumbnailUrl)
|
||||||
return file.exists() && file.delete()
|
return file.exists() && file.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete the cover file from the cache.
|
|
||||||
*
|
|
||||||
* @param thumbnailUrl the thumbnail url.
|
|
||||||
* @return status of deletion.
|
|
||||||
*/
|
|
||||||
fun deleteFromCache(manga: Manga, delayBy:Long) {
|
|
||||||
val thumbnailUrl = manga.thumbnail_url
|
|
||||||
// Check if url is empty.
|
|
||||||
if (thumbnailUrl.isNullOrEmpty()) return
|
|
||||||
launchUI {
|
|
||||||
delay(delayBy)
|
|
||||||
if (!manga.favorite) {
|
|
||||||
// Remove file.
|
|
||||||
val file = getCoverFile(thumbnailUrl)
|
|
||||||
if (file.exists()) file.delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -190,22 +190,6 @@ class DownloadManager(context: Context) {
|
|||||||
cache.removeManga(manga)
|
cache.removeManga(manga)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the directory of a downloaded manga.
|
|
||||||
*
|
|
||||||
* @param manga the manga to delete.
|
|
||||||
* @param source the source of the manga.
|
|
||||||
*/
|
|
||||||
fun deleteManga(manga: Manga, source: Source, delayBy: Long) {
|
|
||||||
launchUI {
|
|
||||||
delay(delayBy)
|
|
||||||
if (!manga.favorite) {
|
|
||||||
deleteManga(manga, source)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a list of chapters to be deleted later.
|
* Adds a list of chapters to be deleted later.
|
||||||
*
|
*
|
||||||
|
@ -64,7 +64,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
ACTION_DELETE_IMAGE -> deleteImage(context, intent.getStringExtra(EXTRA_FILE_LOCATION),
|
||||||
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1))
|
||||||
// Cancel library update and dismiss notification
|
// Cancel library update and dismiss notification
|
||||||
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context, Notifications.ID_LIBRARY_PROGRESS)
|
ACTION_CANCEL_LIBRARY_UPDATE -> cancelLibraryUpdate(context)
|
||||||
// Open reader activity
|
// Open reader activity
|
||||||
ACTION_OPEN_CHAPTER -> {
|
ACTION_OPEN_CHAPTER -> {
|
||||||
openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
openChapter(context, intent.getLongExtra(EXTRA_MANGA_ID, -1),
|
||||||
@ -76,7 +76,8 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
context, notificationId, intent.getStringExtra(EXTRA_GROUP_ID)
|
context, notificationId, intent.getStringExtra(EXTRA_GROUP_ID)
|
||||||
)
|
)
|
||||||
val url = intent.getStringExtra(EXTRA_CHAPTER_URL) ?: return
|
val url = intent.getStringExtra(EXTRA_CHAPTER_URL) ?: return
|
||||||
markAsRead(url)
|
val mangaId = intent.getLongExtra(EXTRA_MANGA_ID, -1)
|
||||||
|
markAsRead(url, mangaId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,9 +158,9 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @param context context of application
|
* @param context context of application
|
||||||
* @param notificationId id of notification
|
* @param notificationId id of notification
|
||||||
*/
|
*/
|
||||||
private fun cancelLibraryUpdate(context: Context, notificationId: Int) {
|
private fun cancelLibraryUpdate(context: Context) {
|
||||||
LibraryUpdateService.stop(context)
|
LibraryUpdateService.stop(context)
|
||||||
Handler().post { dismissNotification(context, notificationId) }
|
Handler().post { dismissNotification(context, Notifications.ID_LIBRARY_PROGRESS) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -168,9 +169,9 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
* @param context context of application
|
* @param context context of application
|
||||||
* @param notificationId id of notification
|
* @param notificationId id of notification
|
||||||
*/
|
*/
|
||||||
private fun markAsRead(chapterUrl: String) {
|
private fun markAsRead(chapterUrl: String, mangaaId: Long) {
|
||||||
val db: DatabaseHelper = Injekt.get()
|
val db: DatabaseHelper = Injekt.get()
|
||||||
val chapter = db.getChapter(chapterUrl).executeAsBlocking() ?: return
|
val chapter = db.getChapter(chapterUrl, mangaaId).executeAsBlocking() ?: return
|
||||||
chapter.read = true
|
chapter.read = true
|
||||||
db.updateChapterProgress(chapter).executeAsBlocking()
|
db.updateChapterProgress(chapter).executeAsBlocking()
|
||||||
val preferences: PreferencesHelper = Injekt.get()
|
val preferences: PreferencesHelper = Injekt.get()
|
||||||
@ -398,6 +399,7 @@ class NotificationReceiver : BroadcastReceiver() {
|
|||||||
val newIntent = Intent(context, NotificationReceiver::class.java).apply {
|
val newIntent = Intent(context, NotificationReceiver::class.java).apply {
|
||||||
action = ACTION_MARK_AS_READ
|
action = ACTION_MARK_AS_READ
|
||||||
putExtra(EXTRA_CHAPTER_URL, chapter.url)
|
putExtra(EXTRA_CHAPTER_URL, chapter.url)
|
||||||
|
putExtra(EXTRA_MANGA_ID, manga.id)
|
||||||
putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode())
|
putExtra(EXTRA_NOTIFICATION_ID, manga.id.hashCode())
|
||||||
putExtra(EXTRA_GROUP_ID, groupId)
|
putExtra(EXTRA_GROUP_ID, groupId)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import android.view.*
|
|||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.f2prateek.rx.preferences.Preference
|
import com.f2prateek.rx.preferences.Preference
|
||||||
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
|
import com.jakewharton.rxbinding.support.v7.widget.queryTextChangeEvents
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
@ -24,6 +25,7 @@ import eu.kanade.tachiyomi.ui.base.controller.SecondaryDrawerController
|
|||||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||||
import eu.kanade.tachiyomi.ui.library.HeightTopWindowInsetsListener
|
import eu.kanade.tachiyomi.ui.library.HeightTopWindowInsetsListener
|
||||||
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.manga.info.MangaWebViewController
|
import eu.kanade.tachiyomi.ui.manga.info.MangaWebViewController
|
||||||
import eu.kanade.tachiyomi.util.*
|
import eu.kanade.tachiyomi.util.*
|
||||||
@ -501,18 +503,23 @@ open class BrowseCatalogueController(bundle: Bundle) :
|
|||||||
* @param position the position of the element clicked.
|
* @param position the position of the element clicked.
|
||||||
*/
|
*/
|
||||||
override fun onItemLongClick(position: Int) {
|
override fun onItemLongClick(position: Int) {
|
||||||
val activity = activity ?: return
|
|
||||||
val manga = (adapter?.getItem(position) as? CatalogueItem?)?.manga ?: return
|
val manga = (adapter?.getItem(position) as? CatalogueItem?)?.manga ?: return
|
||||||
snack?.dismiss()
|
snack?.dismiss()
|
||||||
if (manga.favorite) {
|
if (manga.favorite) {
|
||||||
presenter.changeMangaFavorite(manga)
|
presenter.changeMangaFavorite(manga)
|
||||||
adapter?.notifyItemChanged(position)
|
adapter?.notifyItemChanged(position)
|
||||||
snack =
|
snack = catalouge_layout?.snack(R.string.manga_removed_library, Snackbar.LENGTH_INDEFINITE) {
|
||||||
catalouge_layout?.snack(R.string.manga_removed_library, 5000) {
|
setAction(R.string.action_undo) {
|
||||||
setAction(R.string.action_undo) {
|
if (!manga.favorite) addManga(manga, position)
|
||||||
if (!manga.favorite) addManga(manga, position)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (!manga.favorite) presenter.confirmDeletion(manga)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||||
} else {
|
} else {
|
||||||
addManga(manga, position)
|
addManga(manga, position)
|
||||||
snack = catalouge_layout?.snack(R.string.manga_added_library)
|
snack = catalouge_layout?.snack(R.string.manga_added_library)
|
||||||
|
@ -254,14 +254,15 @@ open class BrowseCataloguePresenter(
|
|||||||
*/
|
*/
|
||||||
fun changeMangaFavorite(manga: Manga) {
|
fun changeMangaFavorite(manga: Manga) {
|
||||||
manga.favorite = !manga.favorite
|
manga.favorite = !manga.favorite
|
||||||
if (!manga.favorite) {
|
|
||||||
coverCache.deleteFromCache(manga, 5000)
|
|
||||||
val downloadManager: DownloadManager = Injekt.get()
|
|
||||||
downloadManager.deleteManga(manga,source,5000)
|
|
||||||
}
|
|
||||||
db.insertManga(manga).executeAsBlocking()
|
db.insertManga(manga).executeAsBlocking()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun confirmDeletion(manga: Manga) {
|
||||||
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
|
val downloadManager: DownloadManager = Injekt.get()
|
||||||
|
downloadManager.deleteManga(manga,source)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the active display mode.
|
* Changes the active display mode.
|
||||||
*/
|
*/
|
||||||
|
@ -171,12 +171,29 @@ open class CatalogueSearchController(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun handleBack(): Boolean {
|
||||||
|
return if (extensionFilter != null) {
|
||||||
|
activity?.finishAffinity()
|
||||||
|
true
|
||||||
|
} else super.handleBack()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add search result to adapter.
|
* Add search result to adapter.
|
||||||
*
|
*
|
||||||
* @param searchResult result of search.
|
* @param searchResult result of search.
|
||||||
*/
|
*/
|
||||||
fun setItems(searchResult: List<CatalogueSearchItem>) {
|
fun setItems(searchResult: List<CatalogueSearchItem>) {
|
||||||
|
if (extensionFilter != null) {
|
||||||
|
val results = searchResult.first().results
|
||||||
|
if (results != null && results.size == 1) {
|
||||||
|
val manga = results.first().manga
|
||||||
|
router.pushController(MangaController(manga,true,fromExtension = true)
|
||||||
|
.withFadeTransaction()
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
adapter?.updateDataSet(searchResult)
|
adapter?.updateDataSet(searchResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.ui.library
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.os.Bundle
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
|
||||||
import com.bluelinelabs.conductor.Controller
|
|
||||||
import eu.kanade.tachiyomi.R
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
|
||||||
import eu.kanade.tachiyomi.widget.DialogCheckboxView
|
|
||||||
|
|
||||||
class DeleteLibraryMangasDialog<T>(bundle: Bundle? = null) :
|
|
||||||
DialogController(bundle) where T : Controller, T: DeleteLibraryMangasDialog.Listener {
|
|
||||||
|
|
||||||
private var mangas = emptyList<Manga>()
|
|
||||||
|
|
||||||
constructor(target: T, mangas: List<Manga>) : this() {
|
|
||||||
this.mangas = mangas
|
|
||||||
targetController = target
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
|
||||||
val view = DialogCheckboxView(activity!!).apply {
|
|
||||||
setDescription(R.string.confirm_delete_manga)
|
|
||||||
setOptionDescription(R.string.also_delete_chapters)
|
|
||||||
}
|
|
||||||
|
|
||||||
return MaterialDialog.Builder(activity!!)
|
|
||||||
.title(R.string.action_remove)
|
|
||||||
.customView(view, true)
|
|
||||||
.positiveText(android.R.string.yes)
|
|
||||||
.negativeText(android.R.string.no)
|
|
||||||
.onPositive { _, _ ->
|
|
||||||
val deleteChapters = view.isChecked()
|
|
||||||
(targetController as? Listener)?.deleteMangasFromLibrary(mangas, deleteChapters)
|
|
||||||
}
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Listener {
|
|
||||||
fun deleteMangasFromLibrary(mangas: List<Manga>, deleteChapters: Boolean)
|
|
||||||
}
|
|
||||||
}
|
|
@ -21,6 +21,7 @@ import androidx.core.view.GravityCompat
|
|||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
import com.f2prateek.rx.preferences.Preference
|
import com.f2prateek.rx.preferences.Preference
|
||||||
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.google.android.material.tabs.TabLayout
|
import com.google.android.material.tabs.TabLayout
|
||||||
import com.jakewharton.rxbinding.support.v4.view.pageSelections
|
import com.jakewharton.rxbinding.support.v4.view.pageSelections
|
||||||
@ -66,7 +67,6 @@ class LibraryController(
|
|||||||
SecondaryDrawerController,
|
SecondaryDrawerController,
|
||||||
ActionMode.Callback,
|
ActionMode.Callback,
|
||||||
ChangeMangaCategoriesDialog.Listener,
|
ChangeMangaCategoriesDialog.Listener,
|
||||||
DeleteLibraryMangasDialog.Listener,
|
|
||||||
MigrationInterface {
|
MigrationInterface {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -530,14 +530,24 @@ class LibraryController(
|
|||||||
|
|
||||||
private fun deleteMangasFromLibrary() {
|
private fun deleteMangasFromLibrary() {
|
||||||
val mangas = selectedMangas.toList()
|
val mangas = selectedMangas.toList()
|
||||||
presenter.removeMangaFromLibrary(mangas, true)
|
presenter.removeMangaFromLibrary(mangas)
|
||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
snack?.dismiss()
|
snack?.dismiss()
|
||||||
snack = view?.snack(activity?.getString(R.string.manga_removed_library) ?: "", 5000) {
|
snack = view?.snack(activity?.getString(R.string.manga_removed_library) ?: "", Snackbar.LENGTH_INDEFINITE) {
|
||||||
|
var undoing = false
|
||||||
setAction(R.string.action_undo) {
|
setAction(R.string.action_undo) {
|
||||||
presenter.addMangas(mangas)
|
presenter.addMangas(mangas)
|
||||||
|
undoing = true
|
||||||
}
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (!undoing)
|
||||||
|
presenter.confirmDeletion(mangas)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateCategoriesForMangas(mangas: List<Manga>, categories: List<Category>) {
|
override fun updateCategoriesForMangas(mangas: List<Manga>, categories: List<Category>) {
|
||||||
@ -545,11 +555,6 @@ class LibraryController(
|
|||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deleteMangasFromLibrary(mangas: List<Manga>, deleteChapters: Boolean) {
|
|
||||||
presenter.removeMangaFromLibrary(mangas, deleteChapters)
|
|
||||||
destroyActionModeIfNeeded()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the cover for the selected manga.
|
* Changes the cover for the selected manga.
|
||||||
*/
|
*/
|
||||||
|
@ -305,7 +305,7 @@ class LibraryPresenter(
|
|||||||
* @param mangas the list of manga to delete.
|
* @param mangas the list of manga to delete.
|
||||||
* @param deleteChapters whether to also delete downloaded chapters.
|
* @param deleteChapters whether to also delete downloaded chapters.
|
||||||
*/
|
*/
|
||||||
fun removeMangaFromLibrary(mangas: List<Manga>, deleteChapters: Boolean) {
|
fun removeMangaFromLibrary(mangas: List<Manga>) {
|
||||||
// Create a set of the list
|
// Create a set of the list
|
||||||
val mangaToDelete = mangas.distinctBy { it.id }
|
val mangaToDelete = mangas.distinctBy { it.id }
|
||||||
mangaToDelete.forEach { it.favorite = false }
|
mangaToDelete.forEach { it.favorite = false }
|
||||||
@ -314,20 +314,18 @@ class LibraryPresenter(
|
|||||||
.onErrorResumeNext { Observable.empty() }
|
.onErrorResumeNext { Observable.empty() }
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.subscribe()
|
.subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun confirmDeletion(mangas: List<Manga>) {
|
||||||
Observable.fromCallable {
|
Observable.fromCallable {
|
||||||
|
val mangaToDelete = mangas.distinctBy { it.id }
|
||||||
mangaToDelete.forEach { manga ->
|
mangaToDelete.forEach { manga ->
|
||||||
coverCache.deleteFromCache(manga, 5000)
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
if (deleteChapters) {
|
val source = sourceManager.get(manga.source) as? HttpSource
|
||||||
val source = sourceManager.get(manga.source) as? HttpSource
|
if (source != null)
|
||||||
if (source != null) {
|
downloadManager.deleteManga(manga, source)
|
||||||
downloadManager.deleteManga(manga, source, 5000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}.subscribeOn(Schedulers.io()).subscribe()
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.subscribe()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addMangas(mangas: List<Manga>) {
|
fun addMangas(mangas: List<Manga>) {
|
||||||
|
@ -5,25 +5,19 @@ import android.app.SearchManager
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.Rect
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.annotation.NonNull
|
import android.view.MotionEvent
|
||||||
import androidx.annotation.Px
|
|
||||||
import androidx.annotation.RequiresApi
|
|
||||||
import androidx.core.view.GravityCompat
|
import androidx.core.view.GravityCompat
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate.*
|
import androidx.appcompat.app.AppCompatDelegate.*
|
||||||
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
|
import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowInsets
|
|
||||||
import android.view.WindowManager
|
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import com.bluelinelabs.conductor.*
|
import com.bluelinelabs.conductor.*
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import eu.kanade.tachiyomi.Migrations
|
import eu.kanade.tachiyomi.Migrations
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||||
@ -34,7 +28,6 @@ import eu.kanade.tachiyomi.ui.catalogue.CatalogueController
|
|||||||
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
||||||
import eu.kanade.tachiyomi.ui.download.DownloadController
|
import eu.kanade.tachiyomi.ui.download.DownloadController
|
||||||
import eu.kanade.tachiyomi.ui.extension.ExtensionController
|
import eu.kanade.tachiyomi.ui.extension.ExtensionController
|
||||||
import eu.kanade.tachiyomi.ui.library.HeightTopWindowInsetsListener
|
|
||||||
import eu.kanade.tachiyomi.ui.library.LibraryController
|
import eu.kanade.tachiyomi.ui.library.LibraryController
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
|
import eu.kanade.tachiyomi.ui.recent_updates.RecentChaptersController
|
||||||
@ -42,17 +35,17 @@ import eu.kanade.tachiyomi.ui.recently_read.RecentlyReadController
|
|||||||
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
import eu.kanade.tachiyomi.ui.setting.SettingsMainController
|
||||||
import eu.kanade.tachiyomi.util.NoopWindowInsetsListener
|
import eu.kanade.tachiyomi.util.NoopWindowInsetsListener
|
||||||
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
|
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
|
||||||
|
import eu.kanade.tachiyomi.util.launchUI
|
||||||
import eu.kanade.tachiyomi.util.marginBottom
|
import eu.kanade.tachiyomi.util.marginBottom
|
||||||
import eu.kanade.tachiyomi.util.marginTop
|
import eu.kanade.tachiyomi.util.marginTop
|
||||||
import eu.kanade.tachiyomi.util.openInBrowser
|
import eu.kanade.tachiyomi.util.openInBrowser
|
||||||
import eu.kanade.tachiyomi.util.updateLayoutParams
|
import eu.kanade.tachiyomi.util.updateLayoutParams
|
||||||
import eu.kanade.tachiyomi.util.updatePadding
|
import eu.kanade.tachiyomi.util.updatePadding
|
||||||
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
||||||
import kotlinx.android.synthetic.main.chapters_controller.view.*
|
|
||||||
import kotlinx.android.synthetic.main.main_activity.*
|
import kotlinx.android.synthetic.main.main_activity.*
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
|
||||||
class MainActivity : BaseActivity() {
|
class MainActivity : BaseActivity() {
|
||||||
|
|
||||||
private lateinit var router: Router
|
private lateinit var router: Router
|
||||||
@ -63,6 +56,25 @@ class MainActivity : BaseActivity() {
|
|||||||
|
|
||||||
private var secondaryDrawer: ViewGroup? = null
|
private var secondaryDrawer: ViewGroup? = null
|
||||||
|
|
||||||
|
private var snackBar:Snackbar? = null
|
||||||
|
var extraRectForUndo:Rect? = null
|
||||||
|
private var canDismissSnackBar = false
|
||||||
|
|
||||||
|
fun setUndoSnackBar(snackBar: Snackbar?, extraViewToCheck: View? = null) {
|
||||||
|
this.snackBar = snackBar
|
||||||
|
canDismissSnackBar = false
|
||||||
|
launchUI {
|
||||||
|
delay(1000)
|
||||||
|
canDismissSnackBar = true
|
||||||
|
}
|
||||||
|
if (extraViewToCheck != null) {
|
||||||
|
extraRectForUndo = Rect()
|
||||||
|
extraViewToCheck.getGlobalVisibleRect(extraRectForUndo)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
extraRectForUndo = null
|
||||||
|
}
|
||||||
|
|
||||||
private val startScreenId by lazy {
|
private val startScreenId by lazy {
|
||||||
when (preferences.startScreen()) {
|
when (preferences.startScreen()) {
|
||||||
2 -> R.id.nav_drawer_recently_read
|
2 -> R.id.nav_drawer_recently_read
|
||||||
@ -296,6 +308,28 @@ class MainActivity : BaseActivity() {
|
|||||||
router.setRoot(controller.withFadeTransaction().tag(id.toString()))
|
router.setRoot(controller.withFadeTransaction().tag(id.toString()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
|
||||||
|
if (ev?.action == MotionEvent.ACTION_DOWN) {
|
||||||
|
if (snackBar != null && snackBar!!.isShown) {
|
||||||
|
val sRect = Rect()
|
||||||
|
snackBar!!.view.getGlobalVisibleRect(sRect)
|
||||||
|
|
||||||
|
//This way the snackbar will only be dismissed if
|
||||||
|
//the user clicks outside it.
|
||||||
|
if (canDismissSnackBar && !sRect.contains(ev.x.toInt(), ev.y.toInt())
|
||||||
|
&& (extraRectForUndo == null ||
|
||||||
|
!extraRectForUndo!!.contains(ev.x.toInt(), ev.y.toInt()))) {
|
||||||
|
snackBar?.dismiss()
|
||||||
|
snackBar = null
|
||||||
|
extraRectForUndo = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (snackBar != null)
|
||||||
|
snackBar = null
|
||||||
|
}
|
||||||
|
return super.dispatchTouchEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
private fun syncActivityViewWithController(to: Controller?, from: Controller? = null) {
|
private fun syncActivityViewWithController(to: Controller?, from: Controller? = null) {
|
||||||
if (from is DialogController || to is DialogController) {
|
if (from is DialogController || to is DialogController) {
|
||||||
return
|
return
|
||||||
|
@ -1,22 +1,20 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga
|
package eu.kanade.tachiyomi.ui.manga
|
||||||
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
import android.app.NotificationManager
|
import android.app.Activity
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.google.android.material.tabs.TabLayout
|
|
||||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
import com.bluelinelabs.conductor.Router
|
import com.bluelinelabs.conductor.Router
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
import com.bluelinelabs.conductor.support.RouterPagerAdapter
|
import com.bluelinelabs.conductor.support.RouterPagerAdapter
|
||||||
|
import com.google.android.material.tabs.TabLayout
|
||||||
import com.jakewharton.rxrelay.BehaviorRelay
|
import com.jakewharton.rxrelay.BehaviorRelay
|
||||||
import com.jakewharton.rxrelay.PublishRelay
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
@ -42,7 +40,10 @@ import java.util.Date
|
|||||||
|
|
||||||
class MangaController : RxController, TabbedController {
|
class MangaController : RxController, TabbedController {
|
||||||
|
|
||||||
constructor(manga: Manga?, fromCatalogue: Boolean = false) : super(Bundle().apply {
|
constructor(manga: Manga?, fromCatalogue: Boolean = false, fromExtension: Boolean = false) :
|
||||||
|
super
|
||||||
|
(Bundle()
|
||||||
|
.apply {
|
||||||
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
putLong(MANGA_EXTRA, manga?.id ?: 0)
|
||||||
putBoolean(FROM_CATALOGUE_EXTRA, fromCatalogue)
|
putBoolean(FROM_CATALOGUE_EXTRA, fromCatalogue)
|
||||||
}) {
|
}) {
|
||||||
@ -50,6 +51,7 @@ class MangaController : RxController, TabbedController {
|
|||||||
if (manga != null) {
|
if (manga != null) {
|
||||||
source = Injekt.get<SourceManager>().getOrStub(manga.source)
|
source = Injekt.get<SourceManager>().getOrStub(manga.source)
|
||||||
}
|
}
|
||||||
|
backClosesApp = fromExtension
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(manga: Manga?, startY:Float?) : super(Bundle().apply {
|
constructor(manga: Manga?, startY:Float?) : super(Bundle().apply {
|
||||||
@ -74,12 +76,32 @@ class MangaController : RxController, TabbedController {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||||
|
backClosesApp = false
|
||||||
|
super.onRestoreInstanceState(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResumed(activity: Activity) {
|
||||||
|
backClosesApp = false
|
||||||
|
super.onActivityResumed(activity)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handleBack(): Boolean {
|
||||||
|
return if (backClosesApp) {
|
||||||
|
activity?.finishAffinity()
|
||||||
|
true
|
||||||
|
} else super.handleBack()
|
||||||
|
}
|
||||||
|
|
||||||
var manga: Manga? = null
|
var manga: Manga? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var source: Source? = null
|
var source: Source? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var backClosesApp = false
|
||||||
|
private set
|
||||||
|
|
||||||
var startingChapterYPos:Float? = null
|
var startingChapterYPos:Float? = null
|
||||||
|
|
||||||
private var adapter: MangaDetailAdapter? = null
|
private var adapter: MangaDetailAdapter? = null
|
||||||
|
@ -34,6 +34,7 @@ import android.content.Context
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import kotlin.math.*
|
import kotlin.math.*
|
||||||
|
|
||||||
class ChaptersController() : NucleusController<ChaptersPresenter>(),
|
class ChaptersController() : NucleusController<ChaptersPresenter>(),
|
||||||
@ -411,19 +412,20 @@ class ChaptersController() : NucleusController<ChaptersPresenter>(),
|
|||||||
val view = view
|
val view = view
|
||||||
destroyActionModeIfNeeded()
|
destroyActionModeIfNeeded()
|
||||||
presenter.downloadChapters(chapters)
|
presenter.downloadChapters(chapters)
|
||||||
if (view != null && !presenter.manga.favorite && (snack == null || snack?.getText() != view.context.getString(R.string.snack_add_to_library))) {
|
if (view != null && !presenter.manga.favorite && (snack == null ||
|
||||||
snack =
|
snack?.getText() != view.context.getString(R.string.snack_add_to_library))) {
|
||||||
view.snack(view.context.getString(R.string.snack_add_to_library), Snackbar.LENGTH_INDEFINITE) {
|
snack = view.snack(view.context.getString(R.string.snack_add_to_library), Snackbar.LENGTH_INDEFINITE) {
|
||||||
setAction(R.string.action_add) {
|
setAction(R.string.action_add) {
|
||||||
presenter.addToLibrary()
|
presenter.addToLibrary()
|
||||||
}
|
|
||||||
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
|
||||||
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
|
||||||
super.onDismissed(transientBottomBar, event)
|
|
||||||
if (snack == transientBottomBar) snack = null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (snack == transientBottomBar) snack = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,18 +11,22 @@ import android.graphics.Bitmap
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.pm.ShortcutInfoCompat
|
import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import android.view.*
|
|
||||||
import android.widget.Toast
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||||
import com.bumptech.glide.request.target.CustomTarget
|
import com.bumptech.glide.request.target.CustomTarget
|
||||||
import com.bumptech.glide.request.target.SimpleTarget
|
|
||||||
import com.bumptech.glide.request.transition.Transition
|
import com.bumptech.glide.request.transition.Transition
|
||||||
|
import com.google.android.material.snackbar.BaseTransientBottomBar
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.jakewharton.rxbinding.support.v4.widget.refreshes
|
import com.jakewharton.rxbinding.support.v4.widget.refreshes
|
||||||
import com.jakewharton.rxbinding.view.clicks
|
import com.jakewharton.rxbinding.view.clicks
|
||||||
import com.jakewharton.rxbinding.view.longClicks
|
import com.jakewharton.rxbinding.view.longClicks
|
||||||
@ -42,7 +46,14 @@ import eu.kanade.tachiyomi.ui.catalogue.global_search.CatalogueSearchController
|
|||||||
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog
|
||||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.util.*
|
import eu.kanade.tachiyomi.util.doOnApplyWindowInsets
|
||||||
|
import eu.kanade.tachiyomi.util.getUriCompat
|
||||||
|
import eu.kanade.tachiyomi.util.marginBottom
|
||||||
|
import eu.kanade.tachiyomi.util.openInBrowser
|
||||||
|
import eu.kanade.tachiyomi.util.snack
|
||||||
|
import eu.kanade.tachiyomi.util.toast
|
||||||
|
import eu.kanade.tachiyomi.util.updateLayoutParams
|
||||||
|
import eu.kanade.tachiyomi.util.updatePaddingRelative
|
||||||
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
import jp.wasabeef.glide.transformations.CropSquareTransformation
|
||||||
import jp.wasabeef.glide.transformations.MaskTransformation
|
import jp.wasabeef.glide.transformations.MaskTransformation
|
||||||
import kotlinx.android.synthetic.main.manga_info_controller.*
|
import kotlinx.android.synthetic.main.manga_info_controller.*
|
||||||
@ -460,11 +471,19 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
val view = container
|
val view = container
|
||||||
snack?.dismiss()
|
snack?.dismiss()
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
snack = view.snack(view.context.getString(R.string.manga_removed_library), 5000) {
|
snack = view.snack(view.context.getString(R.string.manga_removed_library), Snackbar.LENGTH_INDEFINITE) {
|
||||||
setAction(R.string.action_undo) {
|
setAction(R.string.action_undo) {
|
||||||
presenter.setFavorite(true)
|
presenter.setFavorite(true)
|
||||||
}
|
}
|
||||||
|
addCallback(object : BaseTransientBottomBar.BaseCallback<Snackbar>() {
|
||||||
|
override fun onDismissed(transientBottomBar: Snackbar?, event: Int) {
|
||||||
|
super.onDismissed(transientBottomBar, event)
|
||||||
|
if (!presenter.manga.favorite)
|
||||||
|
presenter.confirmDeletion()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
(activity as? MainActivity)?.setUndoSnackBar(snack, fab_favorite)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +499,7 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(),
|
|||||||
val categories = presenter.getCategories()
|
val categories = presenter.getCategories()
|
||||||
if (categories.isEmpty()) {
|
if (categories.isEmpty()) {
|
||||||
// no categories exist, display a message about adding categories
|
// no categories exist, display a message about adding categories
|
||||||
activity?.toast(activity?.getString(R.string.action_add_category))
|
snack = container?.snack(R.string.action_add_category)
|
||||||
} else {
|
} else {
|
||||||
val ids = presenter.getMangaCategoryIds(manga)
|
val ids = presenter.getMangaCategoryIds(manga)
|
||||||
val preselected = ids.mapNotNull { id ->
|
val preselected = ids.mapNotNull { id ->
|
||||||
|
@ -109,15 +109,16 @@ class MangaInfoPresenter(
|
|||||||
*/
|
*/
|
||||||
fun toggleFavorite(): Boolean {
|
fun toggleFavorite(): Boolean {
|
||||||
manga.favorite = !manga.favorite
|
manga.favorite = !manga.favorite
|
||||||
if (!manga.favorite) {
|
|
||||||
coverCache.deleteFromCache(manga, 5000)
|
|
||||||
downloadManager.deleteManga(manga, source, 5000)
|
|
||||||
}
|
|
||||||
db.insertManga(manga).executeAsBlocking()
|
db.insertManga(manga).executeAsBlocking()
|
||||||
sendMangaToView()
|
sendMangaToView()
|
||||||
return manga.favorite
|
return manga.favorite
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun confirmDeletion() {
|
||||||
|
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||||
|
downloadManager.deleteManga(manga, source)
|
||||||
|
}
|
||||||
|
|
||||||
fun setFavorite(favorite: Boolean) {
|
fun setFavorite(favorite: Boolean) {
|
||||||
if (manga.favorite == favorite) {
|
if (manga.favorite == favorite) {
|
||||||
return
|
return
|
||||||
|
@ -89,7 +89,7 @@ class RecentChaptersController : NucleusController<RecentChaptersPresenter>(),
|
|||||||
swipe_refresh.refreshes().subscribeUntilDestroy {
|
swipe_refresh.refreshes().subscribeUntilDestroy {
|
||||||
if (!LibraryUpdateService.isRunning(view.context)) {
|
if (!LibraryUpdateService.isRunning(view.context)) {
|
||||||
LibraryUpdateService.start(view.context)
|
LibraryUpdateService.start(view.context)
|
||||||
view.snack(R.string.action_update_library)
|
view.snack(R.string.updating_library)
|
||||||
}
|
}
|
||||||
// It can be a very long operation, so we disable swipe refresh and show a snackbar.
|
// It can be a very long operation, so we disable swipe refresh and show a snackbar.
|
||||||
swipe_refresh.isRefreshing = false
|
swipe_refresh.isRefreshing = false
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
<string name="action_remove_bookmark">Remove bookmark</string>
|
<string name="action_remove_bookmark">Remove bookmark</string>
|
||||||
<string name="action_delete">Delete</string>
|
<string name="action_delete">Delete</string>
|
||||||
<string name="action_update">Update</string>
|
<string name="action_update">Update</string>
|
||||||
<string name="action_update_library">Updating library</string>
|
<string name="action_update_library">Update library</string>
|
||||||
<string name="action_edit">Edit</string>
|
<string name="action_edit">Edit</string>
|
||||||
<string name="action_add">Add</string>
|
<string name="action_add">Add</string>
|
||||||
<string name="action_add_category">Add category</string>
|
<string name="action_add_category">Add category</string>
|
||||||
@ -317,6 +317,7 @@
|
|||||||
|
|
||||||
<!-- Library fragment -->
|
<!-- Library fragment -->
|
||||||
<string name="library_search_hint">Title or author…</string>
|
<string name="library_search_hint">Title or author…</string>
|
||||||
|
<string name="updating_library">Updating library</string>
|
||||||
<string name="updating_category">Updating category</string>
|
<string name="updating_category">Updating category</string>
|
||||||
<string name="local_source_badge">Local</string>
|
<string name="local_source_badge">Local</string>
|
||||||
<string name="confirm_delete_manga">Are you sure you want to remove selected manga?</string>
|
<string name="confirm_delete_manga">Are you sure you want to remove selected manga?</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user