mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	| @@ -25,3 +25,11 @@ inline fun <K, V, R> Map<out K, V>.mapNotNullKeys(transform: (Map.Entry<K?, V>) | ||||
|     forEach { element -> transform(element)?.let { mutableMap[it] = element.value } } | ||||
|     return mutableMap | ||||
| } | ||||
|  | ||||
| fun <E> HashSet<E>.addOrRemove(value: E, shouldAdd: Boolean) { | ||||
|     if (shouldAdd) { | ||||
|         add(value) | ||||
|     } else { | ||||
|         remove(value) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -31,8 +31,8 @@ class MigrateMangaPresenter( | ||||
|         presenterScope.launchIO { | ||||
|             getFavorites | ||||
|                 .subscribe(sourceId) | ||||
|                 .catch { exception -> | ||||
|                     logcat(LogPriority.ERROR, exception) | ||||
|                 .catch { | ||||
|                     logcat(LogPriority.ERROR, it) | ||||
|                     _events.send(Event.FailedFetchingFavorites) | ||||
|                 } | ||||
|                 .map { list -> | ||||
|   | ||||
| @@ -32,8 +32,8 @@ class MigrationSourcesPresenter( | ||||
|     fun onCreate() { | ||||
|         presenterScope.launchIO { | ||||
|             getSourcesWithFavoriteCount.subscribe() | ||||
|                 .catch { exception -> | ||||
|                     logcat(LogPriority.ERROR, exception) | ||||
|                 .catch { | ||||
|                     logcat(LogPriority.ERROR, it) | ||||
|                     _channel.send(Event.FailedFetchingSourcesWithCount) | ||||
|                 } | ||||
|                 .collectLatest { sources -> | ||||
|   | ||||
| @@ -40,8 +40,8 @@ class SourcesPresenter( | ||||
|     fun onCreate() { | ||||
|         presenterScope.launchIO { | ||||
|             getEnabledSources.subscribe() | ||||
|                 .catch { exception -> | ||||
|                     logcat(LogPriority.ERROR, exception) | ||||
|                 .catch { | ||||
|                     logcat(LogPriority.ERROR, it) | ||||
|                     _events.send(Event.FailedFetchingSources) | ||||
|                 } | ||||
|                 .onStart { delay(500) } // Defer to avoid crashing on initial render | ||||
|   | ||||
| @@ -35,7 +35,7 @@ class DownloadPresenter : BasePresenter<DownloadController>() { | ||||
|  | ||||
|         presenterScope.launch { | ||||
|             downloadQueue.updatedFlow() | ||||
|                 .catch { error -> logcat(LogPriority.ERROR, error) } | ||||
|                 .catch { logcat(LogPriority.ERROR, it) } | ||||
|                 .map { downloads -> | ||||
|                     downloads | ||||
|                         .groupBy { it.source } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import cafe.adriel.voyager.core.model.StateScreenModel | ||||
| import cafe.adriel.voyager.core.model.coroutineScope | ||||
| import eu.kanade.core.prefs.CheckboxState | ||||
| import eu.kanade.core.prefs.mapAsCheckboxState | ||||
| import eu.kanade.core.util.addOrRemove | ||||
| import eu.kanade.data.chapter.NoChaptersException | ||||
| import eu.kanade.domain.base.BasePreferences | ||||
| import eu.kanade.domain.category.interactor.GetCategories | ||||
| @@ -84,6 +85,7 @@ class MangaInfoScreenModel( | ||||
|     basePreferences: BasePreferences = Injekt.get(), | ||||
|     private val downloadPreferences: DownloadPreferences = Injekt.get(), | ||||
|     private val libraryPreferences: LibraryPreferences = Injekt.get(), | ||||
|     private val uiPreferences: UiPreferences = Injekt.get(), | ||||
|     private val trackManager: TrackManager = Injekt.get(), | ||||
|     private val sourceManager: SourceManager = Injekt.get(), | ||||
|     private val downloadManager: DownloadManager = Injekt.get(), | ||||
| @@ -120,6 +122,7 @@ class MangaInfoScreenModel( | ||||
|         get() = successState?.processedChapters | ||||
|  | ||||
|     private val selectedPositions: Array<Int> = arrayOf(-1, -1) // first and last selected index in list | ||||
|     private val selectedChapterIds: HashSet<Long> = HashSet() | ||||
|  | ||||
|     /** | ||||
|      * Helper function to update the UI state only if it's currently in success state | ||||
| @@ -141,7 +144,6 @@ class MangaInfoScreenModel( | ||||
|  | ||||
|     init { | ||||
|         val toChapterItemsParams: List<Chapter>.(manga: Manga) -> List<ChapterItem> = { manga -> | ||||
|             val uiPreferences = Injekt.get<UiPreferences>() | ||||
|             toChapterItems( | ||||
|                 context = context, | ||||
|                 manga = manga, | ||||
| @@ -529,6 +531,7 @@ class MangaInfoScreenModel( | ||||
|                         it + 1, | ||||
|                     ) | ||||
|                 }, | ||||
|                 selected = chapter.id in selectedChapterIds, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| @@ -832,51 +835,54 @@ class MangaInfoScreenModel( | ||||
|     ) { | ||||
|         updateSuccessState { successState -> | ||||
|             val newChapters = successState.processedChapters.toMutableList().apply { | ||||
|                 val modifiedIndex = successState.processedChapters.indexOfFirst { it == item } | ||||
|                 if (modifiedIndex < 0) return@apply | ||||
|                 val selectedIndex = successState.processedChapters.indexOfFirst { it.chapter.id == item.chapter.id } | ||||
|                 if (selectedIndex < 0) return@apply | ||||
|  | ||||
|                 val oldItem = get(modifiedIndex) | ||||
|                 if ((oldItem.selected && selected) || (!oldItem.selected && !selected)) return@apply | ||||
|                 val selectedItem = get(selectedIndex) | ||||
|                 if ((selectedItem.selected && selected) || (!selectedItem.selected && !selected)) return@apply | ||||
|  | ||||
|                 val firstSelection = none { it.selected } | ||||
|                 var newItem = removeAt(modifiedIndex) | ||||
|                 add(modifiedIndex, newItem.copy(selected = selected)) | ||||
|                 set(selectedIndex, selectedItem.copy(selected = selected)) | ||||
|                 selectedChapterIds.addOrRemove(item.chapter.id, selected) | ||||
|  | ||||
|                 if (selected && userSelected && fromLongPress) { | ||||
|                     if (firstSelection) { | ||||
|                         selectedPositions[0] = modifiedIndex | ||||
|                         selectedPositions[1] = modifiedIndex | ||||
|                         selectedPositions[0] = selectedIndex | ||||
|                         selectedPositions[1] = selectedIndex | ||||
|                     } else { | ||||
|                         // Try to select the items in-between when possible | ||||
|                         val range: IntRange | ||||
|                         if (modifiedIndex < selectedPositions[0]) { | ||||
|                             range = modifiedIndex + 1 until selectedPositions[0] | ||||
|                             selectedPositions[0] = modifiedIndex | ||||
|                         } else if (modifiedIndex > selectedPositions[1]) { | ||||
|                             range = (selectedPositions[1] + 1) until modifiedIndex | ||||
|                             selectedPositions[1] = modifiedIndex | ||||
|                         if (selectedIndex < selectedPositions[0]) { | ||||
|                             range = selectedIndex + 1 until selectedPositions[0] | ||||
|                             selectedPositions[0] = selectedIndex | ||||
|                         } else if (selectedIndex > selectedPositions[1]) { | ||||
|                             range = (selectedPositions[1] + 1) until selectedIndex | ||||
|                             selectedPositions[1] = selectedIndex | ||||
|                         } else { | ||||
|                             // Just select itself | ||||
|                             range = IntRange.EMPTY | ||||
|                         } | ||||
|  | ||||
|                         range.forEach { | ||||
|                             newItem = removeAt(it) | ||||
|                             add(it, newItem.copy(selected = true)) | ||||
|                             val inbetweenItem = get(it) | ||||
|                             if (!inbetweenItem.selected) { | ||||
|                                 selectedChapterIds.add(inbetweenItem.chapter.id) | ||||
|                                 set(it, inbetweenItem.copy(selected = true)) | ||||
|                             } | ||||
|                         } | ||||
|                     } | ||||
|                 } else if (userSelected && !fromLongPress) { | ||||
|                     if (!selected) { | ||||
|                         if (modifiedIndex == selectedPositions[0]) { | ||||
|                         if (selectedIndex == selectedPositions[0]) { | ||||
|                             selectedPositions[0] = indexOfFirst { it.selected } | ||||
|                         } else if (modifiedIndex == selectedPositions[1]) { | ||||
|                         } else if (selectedIndex == selectedPositions[1]) { | ||||
|                             selectedPositions[1] = indexOfLast { it.selected } | ||||
|                         } | ||||
|                     } else { | ||||
|                         if (modifiedIndex < selectedPositions[0]) { | ||||
|                             selectedPositions[0] = modifiedIndex | ||||
|                         } else if (modifiedIndex > selectedPositions[1]) { | ||||
|                             selectedPositions[1] = modifiedIndex | ||||
|                         if (selectedIndex < selectedPositions[0]) { | ||||
|                             selectedPositions[0] = selectedIndex | ||||
|                         } else if (selectedIndex > selectedPositions[1]) { | ||||
|                             selectedPositions[1] = selectedIndex | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| @@ -888,6 +894,7 @@ class MangaInfoScreenModel( | ||||
|     fun toggleAllSelection(selected: Boolean) { | ||||
|         updateSuccessState { successState -> | ||||
|             val newChapters = successState.chapters.map { | ||||
|                 selectedChapterIds.addOrRemove(it.chapter.id, selected) | ||||
|                 it.copy(selected = selected) | ||||
|             } | ||||
|             selectedPositions[0] = -1 | ||||
| @@ -899,6 +906,7 @@ class MangaInfoScreenModel( | ||||
|     fun invertSelection() { | ||||
|         updateSuccessState { successState -> | ||||
|             val newChapters = successState.chapters.map { | ||||
|                 selectedChapterIds.addOrRemove(it.chapter.id, !it.selected) | ||||
|                 it.copy(selected = !it.selected) | ||||
|             } | ||||
|             selectedPositions[0] = -1 | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import android.os.Bundle | ||||
| import androidx.compose.runtime.Immutable | ||||
| import androidx.compose.runtime.getValue | ||||
| import androidx.compose.runtime.mutableStateOf | ||||
| import eu.kanade.core.util.addOrRemove | ||||
| import eu.kanade.domain.base.BasePreferences | ||||
| import eu.kanade.domain.chapter.interactor.GetChapter | ||||
| import eu.kanade.domain.chapter.interactor.SetReadStatus | ||||
| @@ -72,6 +73,7 @@ class UpdatesPresenter( | ||||
|  | ||||
|     // First and last selected index in list | ||||
|     private val selectedPositions: Array<Int> = arrayOf(-1, -1) | ||||
|     private val selectedChapterIds: HashSet<Long> = HashSet() | ||||
|  | ||||
|     override fun onCreate(savedState: Bundle?) { | ||||
|         super.onCreate(savedState) | ||||
| @@ -100,7 +102,7 @@ class UpdatesPresenter( | ||||
|  | ||||
|         presenterScope.launchIO { | ||||
|             downloadManager.queue.statusFlow() | ||||
|                 .catch { error -> logcat(LogPriority.ERROR, error) } | ||||
|                 .catch { logcat(LogPriority.ERROR, it) } | ||||
|                 .collect { | ||||
|                     withUIContext { | ||||
|                         updateDownloadState(it) | ||||
| @@ -110,7 +112,7 @@ class UpdatesPresenter( | ||||
|  | ||||
|         presenterScope.launchIO { | ||||
|             downloadManager.queue.progressFlow() | ||||
|                 .catch { error -> logcat(LogPriority.ERROR, error) } | ||||
|                 .catch { logcat(LogPriority.ERROR, it) } | ||||
|                 .collect { | ||||
|                     withUIContext { | ||||
|                         updateDownloadState(it) | ||||
| @@ -120,27 +122,26 @@ class UpdatesPresenter( | ||||
|     } | ||||
|  | ||||
|     private fun List<UpdatesWithRelations>.toUpdateItems(): List<UpdatesItem> { | ||||
|         return this | ||||
|             .distinctBy { it.chapterId } | ||||
|             .map { | ||||
|                 val activeDownload = downloadManager.queue.find { download -> it.chapterId == download.chapter.id } | ||||
|                 val downloaded = downloadManager.isChapterDownloaded( | ||||
|                     it.chapterName, | ||||
|                     it.scanlator, | ||||
|                     it.mangaTitle, | ||||
|                     it.sourceId, | ||||
|                 ) | ||||
|                 val downloadState = when { | ||||
|                     activeDownload != null -> activeDownload.status | ||||
|                     downloaded -> Download.State.DOWNLOADED | ||||
|                     else -> Download.State.NOT_DOWNLOADED | ||||
|                 } | ||||
|                 UpdatesItem( | ||||
|                     update = it, | ||||
|                     downloadStateProvider = { downloadState }, | ||||
|                     downloadProgressProvider = { activeDownload?.progress ?: 0 }, | ||||
|                 ) | ||||
|         return this.map { | ||||
|             val activeDownload = downloadManager.queue.find { download -> it.chapterId == download.chapter.id } | ||||
|             val downloaded = downloadManager.isChapterDownloaded( | ||||
|                 it.chapterName, | ||||
|                 it.scanlator, | ||||
|                 it.mangaTitle, | ||||
|                 it.sourceId, | ||||
|             ) | ||||
|             val downloadState = when { | ||||
|                 activeDownload != null -> activeDownload.status | ||||
|                 downloaded -> Download.State.DOWNLOADED | ||||
|                 else -> Download.State.NOT_DOWNLOADED | ||||
|             } | ||||
|             UpdatesItem( | ||||
|                 update = it, | ||||
|                 downloadStateProvider = { downloadState }, | ||||
|                 downloadProgressProvider = { activeDownload?.progress ?: 0 }, | ||||
|                 selected = it.chapterId in selectedChapterIds, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -155,12 +156,14 @@ class UpdatesPresenter( | ||||
|             } | ||||
|             if (modifiedIndex < 0) return@apply | ||||
|  | ||||
|             val item = removeAt(modifiedIndex) | ||||
|                 .copy( | ||||
|             val item = get(modifiedIndex) | ||||
|             set( | ||||
|                 modifiedIndex, | ||||
|                 item.copy( | ||||
|                     downloadStateProvider = { download.status }, | ||||
|                     downloadProgressProvider = { download.progress }, | ||||
|                 ) | ||||
|             add(modifiedIndex, item) | ||||
|                 ), | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -281,6 +284,7 @@ class UpdatesPresenter( | ||||
|  | ||||
|             val firstSelection = none { it.selected } | ||||
|             set(selectedIndex, selectedItem.copy(selected = selected)) | ||||
|             selectedChapterIds.addOrRemove(item.update.chapterId, selected) | ||||
|  | ||||
|             if (selected && userSelected && fromLongPress) { | ||||
|                 if (firstSelection) { | ||||
| @@ -303,6 +307,7 @@ class UpdatesPresenter( | ||||
|                     range.forEach { | ||||
|                         val inbetweenItem = get(it) | ||||
|                         if (!inbetweenItem.selected) { | ||||
|                             selectedChapterIds.add(inbetweenItem.update.chapterId) | ||||
|                             set(it, inbetweenItem.copy(selected = true)) | ||||
|                         } | ||||
|                     } | ||||
| @@ -327,6 +332,7 @@ class UpdatesPresenter( | ||||
|  | ||||
|     fun toggleAllSelection(selected: Boolean) { | ||||
|         state.items = items.map { | ||||
|             selectedChapterIds.addOrRemove(it.update.chapterId, selected) | ||||
|             it.copy(selected = selected) | ||||
|         } | ||||
|         selectedPositions[0] = -1 | ||||
| @@ -335,6 +341,7 @@ class UpdatesPresenter( | ||||
|  | ||||
|     fun invertSelection() { | ||||
|         state.items = items.map { | ||||
|             selectedChapterIds.addOrRemove(it.update.chapterId, !it.selected) | ||||
|             it.copy(selected = !it.selected) | ||||
|         } | ||||
|         selectedPositions[0] = -1 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user