From 5301cc7f9704cf7ea943384775499a37b65301ed Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 4 Oct 2024 11:20:49 +0300 Subject: [PATCH] Ability to start download paused --- .../core/ui/dialog/CommonAlertDialogs.kt | 25 +++++++++++++++++++ .../ui/pager/ChaptersPagesViewModel.kt | 1 + .../download/ui/worker/DownloadWorker.kt | 21 +++++++++++++--- .../kotatsu/list/ui/MangaListFragment.kt | 9 +++++-- .../kotatsu/list/ui/MangaListViewModel.kt | 4 +-- .../kotatsu/search/ui/multi/SearchActivity.kt | 8 ++++-- .../search/ui/multi/SearchViewModel.kt | 4 +-- .../kotatsu/tracker/work/TrackWorker.kt | 1 + app/src/main/res/values/strings.xml | 3 +++ 9 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/ui/dialog/CommonAlertDialogs.kt diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/dialog/CommonAlertDialogs.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/dialog/CommonAlertDialogs.kt new file mode 100644 index 000000000..22b32d910 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/dialog/CommonAlertDialogs.kt @@ -0,0 +1,25 @@ +package org.koitharu.kotatsu.core.ui.dialog + +import android.content.Context +import androidx.annotation.UiContext +import org.koitharu.kotatsu.R + +object CommonAlertDialogs { + + fun showDownloadConfirmation( + @UiContext context: Context, + onConfirmed: (startPaused: Boolean) -> Unit, + ) = buildAlertDialog(context, isCentered = true) { + var startPaused = false + setTitle(R.string.save_manga) + setIcon(R.drawable.ic_download) + setMessage(R.string.save_manga_confirm) + setCheckbox(R.string.start_download, true) { _, isChecked -> + startPaused = !isChecked + } + setPositiveButton(R.string.save) { _, _ -> + onConfirmed(startPaused) + } + setNegativeButton(android.R.string.cancel, null) + }.show() +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt index 8dca45cf1..ae3517dd1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/ChaptersPagesViewModel.kt @@ -168,6 +168,7 @@ abstract class ChaptersPagesViewModel( downloadScheduler.schedule( manga = requireManga(), chaptersIds = chaptersIds, + isPaused = false, isSilent = false, ) onDownloadStarted.call(Unit) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt index 651be3654..9fe15de56 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt @@ -128,7 +128,11 @@ class DownloadWorker @AssistedInject constructor( val chaptersIds = inputData.getLongArray(CHAPTERS_IDS)?.takeUnless { it.isEmpty() } val downloadedIds = getDoneChapters(manga) return try { - withContext(PausingHandle()) { + val pausingHandle = PausingHandle() + if (inputData.getBoolean(START_PAUSED, false)) { + pausingHandle.pause() + } + withContext(pausingHandle) { downloadMangaImpl(manga, chaptersIds, downloadedIds) } Result.success(currentState.toWorkData()) @@ -431,10 +435,16 @@ class DownloadWorker @AssistedInject constructor( private val settings: AppSettings, ) { - suspend fun schedule(manga: Manga, chaptersIds: Collection?, isSilent: Boolean) { + suspend fun schedule( + manga: Manga, + chaptersIds: Collection?, + isPaused: Boolean, + isSilent: Boolean, + ) { dataRepository.storeManga(manga) val data = Data.Builder() .putLong(MANGA_ID, manga.id) + .putBoolean(START_PAUSED, isPaused) .putBoolean(IS_SILENT, isSilent) if (!chaptersIds.isNullOrEmpty()) { data.putLongArray(CHAPTERS_IDS, chaptersIds.toLongArray()) @@ -442,11 +452,15 @@ class DownloadWorker @AssistedInject constructor( scheduleImpl(listOf(data.build())) } - suspend fun schedule(manga: Collection) { + suspend fun schedule( + manga: Collection, + isPaused: Boolean, + ) { val data = manga.map { dataRepository.storeManga(it) Data.Builder() .putLong(MANGA_ID, it.id) + .putBoolean(START_PAUSED, isPaused) .build() } scheduleImpl(data) @@ -556,6 +570,7 @@ class DownloadWorker @AssistedInject constructor( const val MANGA_ID = "manga_id" const val CHAPTERS_IDS = "chapters" const val IS_SILENT = "silent" + const val START_PAUSED = "paused" const val TAG = "download" } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt index 4efd19b52..771ac4103 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListFragment.kt @@ -27,6 +27,7 @@ import org.koitharu.kotatsu.core.model.isLocal import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ListMode import org.koitharu.kotatsu.core.ui.BaseFragment +import org.koitharu.kotatsu.core.ui.dialog.CommonAlertDialogs import org.koitharu.kotatsu.core.ui.dialog.buildAlertDialog import org.koitharu.kotatsu.core.ui.list.FitHeightGridLayoutManager import org.koitharu.kotatsu.core.ui.list.FitHeightLinearLayoutManager @@ -238,6 +239,7 @@ abstract class MangaListFragment : } override fun onFilterOptionClick(option: ListFilterOption) { + selectionController?.clear() (viewModel as? QuickFilterListener)?.toggleFilterOption(option) } @@ -322,8 +324,11 @@ abstract class MangaListFragment : } R.id.action_save -> { - viewModel.download(selectedItems) - mode?.finish() + val itemsSnapshot = selectedItems + CommonAlertDialogs.showDownloadConfirmation(context ?: return false) { startPaused -> + mode?.finish() + viewModel.download(itemsSnapshot, isPaused = startPaused) + } true } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt index 0090b8e10..700c26e62 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/list/ui/MangaListViewModel.kt @@ -46,9 +46,9 @@ abstract class MangaListViewModel( abstract fun onRetry() - fun download(items: Set) { + fun download(items: Set, isPaused: Boolean) { launchJob(Dispatchers.Default) { - downloadScheduler.schedule(items) + downloadScheduler.schedule(items, isPaused) onDownloadStarted.call(Unit) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchActivity.kt index 975dad0d4..095f817f6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchActivity.kt @@ -17,6 +17,7 @@ import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.ui.BaseActivity +import org.koitharu.kotatsu.core.ui.dialog.CommonAlertDialogs import org.koitharu.kotatsu.core.ui.list.ListSelectionController import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener import org.koitharu.kotatsu.core.ui.widgets.TipView @@ -184,8 +185,11 @@ class SearchActivity : } R.id.action_save -> { - viewModel.download(collectSelectedItems()) - mode?.finish() + val itemsSnapshot = collectSelectedItems() + CommonAlertDialogs.showDownloadConfirmation(this) { startPaused -> + mode?.finish() + viewModel.download(itemsSnapshot, isPaused = startPaused) + } true } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchViewModel.kt index 3edd17e9e..c0d3d52aa 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/search/ui/multi/SearchViewModel.kt @@ -109,9 +109,9 @@ class SearchViewModel @Inject constructor( retryCounter.value += 1 } - fun download(items: Set) { + fun download(items: Set, isPaused: Boolean) { launchJob(Dispatchers.Default) { - downloadScheduler.schedule(items) + downloadScheduler.schedule(items, isPaused) onDownloadStarted.call(Unit) } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt index 0c2cc96c8..4b2d3b9c1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt @@ -254,6 +254,7 @@ class TrackWorker @AssistedInject constructor( downloadSchedulerLazy.get().schedule( manga = mangaUpdates.manga, chaptersIds = mangaUpdates.newChapters.mapToSet { it.id }, + isPaused = false, isSilent = true, ) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a5bcf862c..c1b0ecfaa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -738,4 +738,7 @@ User manual Telegram group Unsupported image format: %s + Start download + Save selected manga? This may consume traffic and disk space + Save manga