Delete local manga
This commit is contained in:
@@ -27,7 +27,11 @@
|
||||
android:name="android.app.default_searchable"
|
||||
android:value=".ui.search.SearchActivity" />
|
||||
</activity>
|
||||
<activity android:name=".ui.details.MangaDetailsActivity" />
|
||||
<activity android:name=".ui.details.MangaDetailsActivity" >
|
||||
<intent-filter>
|
||||
<action android:name="${applicationId}.action.VIEW_MANGA" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ui.reader.ReaderActivity" />
|
||||
<activity
|
||||
android:name=".ui.search.SearchActivity"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.koitharu.kotatsu.ui.common
|
||||
package org.koitharu.kotatsu.ui.common.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
@@ -71,7 +71,8 @@ class TextInputDialog private constructor(private val delegate: AlertDialog) :
|
||||
return this
|
||||
}
|
||||
|
||||
fun create() = TextInputDialog(delegate.create())
|
||||
fun create() =
|
||||
TextInputDialog(delegate.create())
|
||||
|
||||
}
|
||||
}
|
||||
@@ -49,9 +49,9 @@ class ChaptersFragment : BaseFragment(R.layout.fragment_chapters), MangaDetailsV
|
||||
progressBar.isVisible = isLoading
|
||||
}
|
||||
|
||||
override fun onError(e: Exception) {
|
||||
override fun onError(e: Exception) = Unit //handled in activity
|
||||
|
||||
}
|
||||
override fun onMangaRemoved(manga: Manga) = Unit //handled in activity
|
||||
|
||||
override fun onHistoryChanged(history: MangaHistory?) {
|
||||
adapter.currentChapterId = history?.chapterId
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.net.toFile
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@@ -25,6 +26,7 @@ import org.koitharu.kotatsu.ui.download.DownloadService
|
||||
import org.koitharu.kotatsu.utils.ShareHelper
|
||||
import org.koitharu.kotatsu.utils.ShortcutUtils
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.showDialog
|
||||
|
||||
class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
|
||||
@@ -58,6 +60,14 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
|
||||
override fun onLoadingStateChanged(isLoading: Boolean) = Unit
|
||||
|
||||
override fun onMangaRemoved(manga: Manga) {
|
||||
Toast.makeText(
|
||||
this, getString(R.string._s_deleted_from_local_storage, manga.title),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onError(e: Exception) {
|
||||
Snackbar.make(pager, e.getDisplayMessage(resources), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
@@ -68,9 +78,11 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
|
||||
menu.findItem(R.id.action_save).isEnabled =
|
||||
menu.findItem(R.id.action_save).isVisible =
|
||||
manga?.source != null && manga?.source != MangaSource.LOCAL
|
||||
menu.findItem(R.id.action_shortcut).isVisible = BuildConfig.DEBUG ||
|
||||
menu.findItem(R.id.action_delete).isVisible =
|
||||
manga?.source == MangaSource.LOCAL
|
||||
menu.findItem(R.id.action_shortcut).isVisible = BuildConfig.DEBUG &&
|
||||
ShortcutManagerCompat.isRequestPinShortcutSupported(this)
|
||||
return super.onPrepareOptionsMenu(menu)
|
||||
}
|
||||
@@ -86,6 +98,19 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
}
|
||||
true
|
||||
}
|
||||
R.id.action_delete -> {
|
||||
manga?.let { m ->
|
||||
showDialog {
|
||||
setTitle(R.string.delete_manga)
|
||||
setMessage(getString(R.string.text_delete_local_manga, m.title))
|
||||
setPositiveButton(R.string.delete) { _, _ ->
|
||||
presenter.deleteLocal(m)
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
R.id.action_save -> {
|
||||
manga?.let {
|
||||
DownloadService.start(this, it)
|
||||
@@ -118,6 +143,8 @@ class MangaDetailsActivity : BaseActivity(), MangaDetailsView {
|
||||
|
||||
private const val EXTRA_MANGA = "manga"
|
||||
|
||||
const val ACTION_MANGA_VIEW = "${BuildConfig.APPLICATION_ID}.action.VIEW_MANGA"
|
||||
|
||||
fun newIntent(context: Context, manga: Manga) =
|
||||
Intent(context, MangaDetailsActivity::class.java)
|
||||
.putExtra(EXTRA_MANGA, manga)
|
||||
|
||||
@@ -82,9 +82,9 @@ class MangaDetailsFragment : BaseFragment(R.layout.fragment_details), MangaDetai
|
||||
progressBar.isVisible = isLoading
|
||||
}
|
||||
|
||||
override fun onError(e: Exception) {
|
||||
override fun onError(e: Exception) = Unit //handled in activity
|
||||
|
||||
}
|
||||
override fun onMangaRemoved(manga: Manga) = Unit //handled in activity
|
||||
|
||||
private fun updateReadButton() {
|
||||
if (manga?.chapters.isNullOrEmpty()) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.koitharu.kotatsu.ui.details
|
||||
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -7,15 +8,20 @@ import moxy.InjectViewState
|
||||
import moxy.presenterScope
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaSource
|
||||
import org.koitharu.kotatsu.core.parser.LocalMangaRepository
|
||||
import org.koitharu.kotatsu.domain.MangaProviderFactory
|
||||
import org.koitharu.kotatsu.domain.favourites.FavouritesRepository
|
||||
import org.koitharu.kotatsu.domain.favourites.OnFavouritesChangeListener
|
||||
import org.koitharu.kotatsu.domain.history.HistoryRepository
|
||||
import org.koitharu.kotatsu.domain.history.OnHistoryChangeListener
|
||||
import org.koitharu.kotatsu.ui.common.BasePresenter
|
||||
import org.koitharu.kotatsu.utils.ext.safe
|
||||
import java.io.IOException
|
||||
|
||||
@InjectViewState
|
||||
class MangaDetailsPresenter private constructor(): BasePresenter<MangaDetailsView>(), OnHistoryChangeListener,
|
||||
class MangaDetailsPresenter private constructor() : BasePresenter<MangaDetailsView>(),
|
||||
OnHistoryChangeListener,
|
||||
OnFavouritesChangeListener {
|
||||
|
||||
private lateinit var historyRepository: HistoryRepository
|
||||
@@ -57,6 +63,31 @@ class MangaDetailsPresenter private constructor(): BasePresenter<MangaDetailsVie
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteLocal(manga: Manga) {
|
||||
presenterScope.launch {
|
||||
viewState.onLoadingStateChanged(true)
|
||||
try {
|
||||
withContext(Dispatchers.IO) {
|
||||
val repository =
|
||||
MangaProviderFactory.create(MangaSource.LOCAL) as LocalMangaRepository
|
||||
repository.delete(manga) || throw IOException("Unable to delete file")
|
||||
safe {
|
||||
HistoryRepository().delete(manga)
|
||||
}
|
||||
}
|
||||
viewState.onMangaRemoved(manga)
|
||||
} catch (e: CancellationException) {
|
||||
} catch (e: Exception) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
viewState.onError(e)
|
||||
} finally {
|
||||
viewState.onLoadingStateChanged(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadHistory(manga: Manga) {
|
||||
presenterScope.launch {
|
||||
try {
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.ui.details
|
||||
import moxy.MvpView
|
||||
import moxy.viewstate.strategy.alias.AddToEndSingle
|
||||
import moxy.viewstate.strategy.alias.OneExecution
|
||||
import moxy.viewstate.strategy.alias.SingleState
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.core.model.MangaHistory
|
||||
@@ -23,4 +24,7 @@ interface MangaDetailsView : MvpView {
|
||||
|
||||
@AddToEndSingle
|
||||
fun onFavouriteChanged(categories: List<FavouriteCategory>)
|
||||
|
||||
@SingleState
|
||||
fun onMangaRemoved(manga: Manga)
|
||||
}
|
||||
@@ -49,7 +49,7 @@ class DownloadNotification(private val context: Context) {
|
||||
chapter * PROGRESS_STEP + (page / pagesTotal.toFloat() * PROGRESS_STEP).roundToInt()
|
||||
val percent = (progress / max.toFloat() * 100).roundToInt()
|
||||
builder.setProgress(max, progress, false)
|
||||
builder.setContentText(context.getString(R.string.downloading_d_percent, percent))
|
||||
builder.setContentText("%d%%".format(percent))
|
||||
}
|
||||
|
||||
fun setPostProcessing() {
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.ui.common.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.ui.common.TextInputDialog
|
||||
import org.koitharu.kotatsu.ui.common.dialog.TextInputDialog
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.ui.main.list.MangaListFragment
|
||||
import org.koitharu.kotatsu.utils.ext.ellipsize
|
||||
import org.koitharu.kotatsu.utils.ext.showDialog
|
||||
import java.io.File
|
||||
|
||||
class LocalListFragment : MangaListFragment<File>() {
|
||||
@@ -80,7 +81,14 @@ class LocalListFragment : MangaListFragment<File>() {
|
||||
override fun onPopupMenuItemSelected(item: MenuItem, data: Manga): Boolean {
|
||||
return when (item.itemId) {
|
||||
R.id.action_delete -> {
|
||||
presenter.delete(data)
|
||||
context?.showDialog {
|
||||
setTitle(R.string.delete_manga)
|
||||
setMessage(getString(R.string.text_delete_local_manga, data.title))
|
||||
setPositiveButton(R.string.delete) { _, _ ->
|
||||
presenter.delete(data)
|
||||
}
|
||||
setNegativeButton(android.R.string.cancel, null)
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> super.onPopupMenuItemSelected(item, data)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.koitharu.kotatsu.utils
|
||||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.content.pm.ShortcutInfoCompat
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
@@ -11,23 +13,30 @@ import kotlinx.coroutines.withContext
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.Manga
|
||||
import org.koitharu.kotatsu.ui.details.MangaDetailsActivity
|
||||
import org.koitharu.kotatsu.utils.ext.safe
|
||||
|
||||
object ShortcutUtils {
|
||||
|
||||
@JvmStatic
|
||||
suspend fun createShortcutInfo(context: Context, manga: Manga): ShortcutInfoCompat {
|
||||
// val icon = withContext(Dispatchers.IO) {
|
||||
// Coil.loader().get(manga.coverUrl) {
|
||||
// context.getSystemService<ActivityManager>()?.let {
|
||||
// size(it.launcherLargeIconSize)
|
||||
// }
|
||||
// }.toBitmap()
|
||||
// }
|
||||
val icon = safe {
|
||||
withContext(Dispatchers.IO) {
|
||||
Coil.loader().get(manga.coverUrl) {
|
||||
context.getSystemService<ActivityManager>()?.let {
|
||||
size(it.launcherLargeIconSize)
|
||||
}
|
||||
}.toBitmap()
|
||||
}
|
||||
}
|
||||
return ShortcutInfoCompat.Builder(context, manga.id.toString())
|
||||
.setShortLabel(manga.title)
|
||||
.setLongLabel(manga.title)
|
||||
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_launcher_foreground))
|
||||
.setIntent(MangaDetailsActivity.newIntent(context, manga))
|
||||
.setIcon(icon?.let {
|
||||
IconCompat.createWithBitmap(it)
|
||||
} ?: IconCompat.createWithResource(context, R.drawable.ic_launcher_foreground))
|
||||
.setIntent(
|
||||
MangaDetailsActivity.newIntent(context, manga.copy(chapters = null))
|
||||
.setAction(MangaDetailsActivity.ACTION_MANGA_VIEW)
|
||||
)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:icon="@drawable/ic_share"
|
||||
android:title="@string/share"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:icon="@drawable/ic_share"
|
||||
android:title="@string/share"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_save"
|
||||
android:title="@string/save"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_save"
|
||||
android:title="@string/save"
|
||||
android:visible="false"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shortcut"
|
||||
android:title="@string/create_shortcut"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_delete"
|
||||
android:title="@string/delete"
|
||||
android:visible="false"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_shortcut"
|
||||
android:title="@string/create_shortcut"
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
@@ -86,4 +86,6 @@
|
||||
<string name="put_items_below_to_disable_it">Put items below to disable it</string>
|
||||
<string name="grid_size">Grid size</string>
|
||||
<string name="search_results_on_s">Search results on %s</string>
|
||||
<string name="delete_manga">Delete manga</string>
|
||||
<string name="text_delete_local_manga">Are you really want to delete \"%s\" from your phone\'s local storage? \nThis operation cannot be undone.</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user