Ask for chapter deletion when removing from library

This commit is contained in:
len 2017-02-03 20:14:33 +01:00
parent b66f06d9dc
commit f7c791d153
6 changed files with 85 additions and 18 deletions

View File

@ -25,6 +25,7 @@ import eu.kanade.tachiyomi.ui.category.CategoryActivity
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.util.inflate
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import eu.kanade.tachiyomi.widget.DialogCheckboxView
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_library.* import kotlinx.android.synthetic.main.fragment_library.*
import nucleus.factory.RequiresPresenter import nucleus.factory.RequiresPresenter
@ -480,12 +481,19 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
} }
private fun showDeleteMangaDialog() { private fun showDeleteMangaDialog() {
val view = DialogCheckboxView(context).apply {
setDescription(R.string.confirm_delete_manga)
setOptionDescription(R.string.also_delete_chapters)
}
MaterialDialog.Builder(activity) MaterialDialog.Builder(activity)
.content(R.string.confirm_delete_manga) .title(R.string.action_remove)
.customView(view, true)
.positiveText(android.R.string.yes) .positiveText(android.R.string.yes)
.negativeText(android.R.string.no) .negativeText(android.R.string.no)
.onPositive { dialog, action -> .onPositive { dialog, action ->
presenter.removeMangaFromLibrary() val deleteChapters = view.isChecked()
presenter.removeMangaFromLibrary(deleteChapters)
destroyActionModeIfNeeded() destroyActionModeIfNeeded()
} }
.show() .show()

View File

@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.util.combineLatest import eu.kanade.tachiyomi.util.combineLatest
import eu.kanade.tachiyomi.util.isNullOrUnsubscribed import eu.kanade.tachiyomi.util.isNullOrUnsubscribed
@ -303,19 +304,31 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
/** /**
* Remove the selected manga from the library. * Remove the selected manga from the library.
*
* @param deleteChapters whether to also delete downloaded chapters.
*/ */
fun removeMangaFromLibrary() { fun removeMangaFromLibrary(deleteChapters: Boolean) {
// Create a set of the list // Create a set of the list
val mangaToDelete = selectedMangas.toSet() val mangaToDelete = selectedMangas.distinctBy { it.id }
mangaToDelete.forEach { it.favorite = false }
Observable.from(mangaToDelete) Observable.fromCallable { db.insertMangas(mangaToDelete).executeAsBlocking() }
.onErrorResumeNext { Observable.empty() }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.doOnNext { .subscribe()
it.favorite = false
coverCache.deleteFromCache(it.thumbnail_url) Observable.fromCallable {
mangaToDelete.forEach { manga ->
coverCache.deleteFromCache(manga.thumbnail_url)
if (deleteChapters) {
val source = sourceManager.get(manga.source) as? HttpSource
if (source != null) {
downloadManager.findMangaDir(source, manga)?.delete()
} }
.toList() }
.flatMap { db.insertMangas(it).asRxObservable() } }
}
.subscribeOn(Schedulers.io())
.subscribe() .subscribe()
} }

View File

@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
import eu.kanade.tachiyomi.ui.manga.MangaActivity import eu.kanade.tachiyomi.ui.manga.MangaActivity
import eu.kanade.tachiyomi.util.getResourceColor import eu.kanade.tachiyomi.util.getResourceColor
import eu.kanade.tachiyomi.util.snack
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import jp.wasabeef.glide.transformations.CropCircleTransformation import jp.wasabeef.glide.transformations.CropCircleTransformation
import jp.wasabeef.glide.transformations.CropSquareTransformation import jp.wasabeef.glide.transformations.CropSquareTransformation
@ -62,7 +63,7 @@ class MangaInfoFragment : BaseRxFragment<MangaInfoPresenter>() {
override fun onViewCreated(view: View?, savedState: Bundle?) { override fun onViewCreated(view: View?, savedState: Bundle?) {
// Set onclickListener to toggle favorite when FAB clicked. // Set onclickListener to toggle favorite when FAB clicked.
fab_favorite.setOnClickListener { presenter.toggleFavorite() } fab_favorite.setOnClickListener { toggleFavorite() }
// Set SwipeRefresh to refresh manga data. // Set SwipeRefresh to refresh manga data.
swipe_refresh.setOnRefreshListener { fetchMangaFromSource() } swipe_refresh.setOnRefreshListener { fetchMangaFromSource() }
@ -160,13 +161,31 @@ class MangaInfoFragment : BaseRxFragment<MangaInfoPresenter>() {
manga_chapters.text = count.toString() manga_chapters.text = count.toString()
} }
/**
* Toggles the favorite status and asks for confirmation to delete downloaded chapters.
*/
fun toggleFavorite() {
if (!isAdded) return
val isNowFavorite = presenter.toggleFavorite()
if (!isNowFavorite && presenter.hasDownloads()) {
view!!.snack(getString(R.string.delete_downloads_for_manga)) {
setAction(R.string.action_delete) {
presenter.deleteDownloads()
}
}
}
}
/** /**
* Open the manga in browser. * Open the manga in browser.
*/ */
fun openInBrowser() { fun openInBrowser() {
if (!isAdded) return
val source = presenter.source as? HttpSource ?: return val source = presenter.source as? HttpSource ?: return
try { try {
val url = Uri.parse(source.baseUrl + presenter.manga.url) val url = Uri.parse(source.mangaDetailsRequest(presenter.manga).url().toString())
val intent = CustomTabsIntent.Builder() val intent = CustomTabsIntent.Builder()
.setToolbarColor(context.getResourceColor(R.attr.colorPrimary)) .setToolbarColor(context.getResourceColor(R.attr.colorPrimary))
.build() .build()
@ -180,14 +199,16 @@ class MangaInfoFragment : BaseRxFragment<MangaInfoPresenter>() {
* Called to run Intent with [Intent.ACTION_SEND], which show share dialog. * Called to run Intent with [Intent.ACTION_SEND], which show share dialog.
*/ */
private fun shareManga() { private fun shareManga() {
if (!isAdded) return
val source = presenter.source as? HttpSource ?: return val source = presenter.source as? HttpSource ?: return
try { try {
val url = source.mangaDetailsRequest(presenter.manga).url().toString() val url = source.mangaDetailsRequest(presenter.manga).url().toString()
val sharingIntent = Intent(Intent.ACTION_SEND).apply { val sharingIntent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain" type = "text/plain"
putExtra(android.content.Intent.EXTRA_TEXT, resources.getString(R.string.share_text, presenter.manga.title, url)) putExtra(Intent.EXTRA_TEXT, getString(R.string.share_text, presenter.manga.title, url))
} }
startActivity(Intent.createChooser(sharingIntent, resources.getText(R.string.action_share))) startActivity(Intent.createChooser(sharingIntent, getString(R.string.action_share)))
} catch (e: Exception) { } catch (e: Exception) {
context.toast(e.message) context.toast(e.message)
} }
@ -197,6 +218,8 @@ class MangaInfoFragment : BaseRxFragment<MangaInfoPresenter>() {
* Add the manga to the home screen * Add the manga to the home screen
*/ */
fun addToHomeScreen() { fun addToHomeScreen() {
if (!isAdded) return
val shortcutIntent = activity.intent val shortcutIntent = activity.intent
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.putExtra(MangaActivity.FROM_LAUNCHER_EXTRA, true) .putExtra(MangaActivity.FROM_LAUNCHER_EXTRA, true)

View File

@ -4,6 +4,7 @@ import android.os.Bundle
import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
@ -50,6 +51,8 @@ class MangaInfoPresenter : BasePresenter<MangaInfoFragment>() {
*/ */
val coverCache: CoverCache by injectLazy() val coverCache: CoverCache by injectLazy()
private val downloadManager: DownloadManager by injectLazy()
/** /**
* Subscription to send the manga to the view. * Subscription to send the manga to the view.
*/ */
@ -75,7 +78,7 @@ class MangaInfoPresenter : BasePresenter<MangaInfoFragment>() {
// Update favorite status // Update favorite status
SharedData.get(MangaFavoriteEvent::class.java)?.observable SharedData.get(MangaFavoriteEvent::class.java)?.observable
?.observeOn(AndroidSchedulers.mainThread()) ?.observeOn(AndroidSchedulers.mainThread())
?.subscribe{setFavorite(it)} ?.subscribe { setFavorite(it) }
} }
/** /**
@ -111,14 +114,17 @@ class MangaInfoPresenter : BasePresenter<MangaInfoFragment>() {
/** /**
* Update favorite status of manga, (removes / adds) manga (to / from) library. * Update favorite status of manga, (removes / adds) manga (to / from) library.
*
* @return the new status of the manga.
*/ */
fun toggleFavorite() { fun toggleFavorite(): Boolean {
manga.favorite = !manga.favorite manga.favorite = !manga.favorite
if (!manga.favorite) { if (!manga.favorite) {
coverCache.deleteFromCache(manga.thumbnail_url) coverCache.deleteFromCache(manga.thumbnail_url)
} }
db.insertManga(manga).executeAsBlocking() db.insertManga(manga).executeAsBlocking()
sendMangaToView() sendMangaToView()
return manga.favorite
} }
private fun setFavorite(favorite: Boolean) { private fun setFavorite(favorite: Boolean) {
@ -128,4 +134,18 @@ class MangaInfoPresenter : BasePresenter<MangaInfoFragment>() {
toggleFavorite() toggleFavorite()
} }
/**
* Returns true if the manga has any downloads.
*/
fun hasDownloads(): Boolean {
return downloadManager.findMangaDir(source, manga) != null
}
/**
* Deletes all the downloads for the manga.
*/
fun deleteDownloads() {
downloadManager.findMangaDir(source, manga)?.delete()
}
} }

View File

@ -4,14 +4,15 @@ import android.content.Context
import android.support.annotation.StringRes import android.support.annotation.StringRes
import android.util.AttributeSet import android.util.AttributeSet
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.RelativeLayout
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.inflate
import kotlinx.android.synthetic.main.dialog_with_checkbox.view.* import kotlinx.android.synthetic.main.dialog_with_checkbox.view.*
class DialogCheckboxView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : class DialogCheckboxView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
LinearLayout(context, attrs) { LinearLayout(context, attrs) {
init { init {
RelativeLayout.inflate(context, R.layout.dialog_with_checkbox, this) addView(inflate(R.layout.dialog_with_checkbox))
} }
fun setDescription(@StringRes id: Int){ fun setDescription(@StringRes id: Int){

View File

@ -218,6 +218,7 @@
<string name="library_search_hint">Title or author…</string> <string name="library_search_hint">Title or author…</string>
<string name="updating_category">Updating category</string> <string name="updating_category">Updating category</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>
<string name="also_delete_chapters">Also delete downloaded chapters</string>
<!-- Catalogue fragment --> <!-- Catalogue fragment -->
<string name="source_requires_login">This source requires you to log in</string> <string name="source_requires_login">This source requires you to log in</string>
@ -251,6 +252,7 @@
<string name="shortcut_title">Shortcut title</string> <string name="shortcut_title">Shortcut title</string>
<string name="icon_shape">Icon shape</string> <string name="icon_shape">Icon shape</string>
<string name="icon_creation_fail">Failed to create shortcut!</string> <string name="icon_creation_fail">Failed to create shortcut!</string>
<string name="delete_downloads_for_manga">Delete downloaded chapters?</string>
<!-- Manga chapters fragment --> <!-- Manga chapters fragment -->
<string name="manga_chapters_tab">Chapters</string> <string name="manga_chapters_tab">Chapters</string>