mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Support mass migration in 'Browse -> Migrate' (#2338)
This commit is contained in:
		| @@ -1,84 +0,0 @@ | ||||
| package eu.kanade.presentation.browse | ||||
|  | ||||
| import androidx.compose.foundation.layout.PaddingValues | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.lazy.items | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.ui.Modifier | ||||
| import eu.kanade.presentation.components.AppBar | ||||
| import eu.kanade.presentation.manga.components.BaseMangaListItem | ||||
| import eu.kanade.tachiyomi.ui.browse.migration.manga.MigrateMangaScreenModel | ||||
| import tachiyomi.domain.manga.model.Manga | ||||
| import tachiyomi.i18n.MR | ||||
| import tachiyomi.presentation.core.components.FastScrollLazyColumn | ||||
| import tachiyomi.presentation.core.components.material.Scaffold | ||||
| import tachiyomi.presentation.core.screens.EmptyScreen | ||||
|  | ||||
| @Composable | ||||
| fun MigrateMangaScreen( | ||||
|     navigateUp: () -> Unit, | ||||
|     title: String?, | ||||
|     state: MigrateMangaScreenModel.State, | ||||
|     onClickItem: (Manga) -> Unit, | ||||
|     onClickCover: (Manga) -> Unit, | ||||
| ) { | ||||
|     Scaffold( | ||||
|         topBar = { scrollBehavior -> | ||||
|             AppBar( | ||||
|                 title = title, | ||||
|                 navigateUp = navigateUp, | ||||
|                 scrollBehavior = scrollBehavior, | ||||
|             ) | ||||
|         }, | ||||
|     ) { contentPadding -> | ||||
|         if (state.isEmpty) { | ||||
|             EmptyScreen( | ||||
|                 stringRes = MR.strings.empty_screen, | ||||
|                 modifier = Modifier.padding(contentPadding), | ||||
|             ) | ||||
|             return@Scaffold | ||||
|         } | ||||
|  | ||||
|         MigrateMangaContent( | ||||
|             contentPadding = contentPadding, | ||||
|             state = state, | ||||
|             onClickItem = onClickItem, | ||||
|             onClickCover = onClickCover, | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| private fun MigrateMangaContent( | ||||
|     contentPadding: PaddingValues, | ||||
|     state: MigrateMangaScreenModel.State, | ||||
|     onClickItem: (Manga) -> Unit, | ||||
|     onClickCover: (Manga) -> Unit, | ||||
| ) { | ||||
|     FastScrollLazyColumn( | ||||
|         contentPadding = contentPadding, | ||||
|     ) { | ||||
|         items(state.titles) { manga -> | ||||
|             MigrateMangaItem( | ||||
|                 manga = manga, | ||||
|                 onClickItem = onClickItem, | ||||
|                 onClickCover = onClickCover, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| private fun MigrateMangaItem( | ||||
|     manga: Manga, | ||||
|     onClickItem: (Manga) -> Unit, | ||||
|     onClickCover: (Manga) -> Unit, | ||||
|     modifier: Modifier = Modifier, | ||||
| ) { | ||||
|     BaseMangaListItem( | ||||
|         modifier = modifier, | ||||
|         manga = manga, | ||||
|         onClickItem = { onClickItem(manga) }, | ||||
|         onClickCover = { onClickCover(manga) }, | ||||
|     ) | ||||
| } | ||||
| @@ -1,21 +1,41 @@ | ||||
| package eu.kanade.tachiyomi.ui.browse.migration.manga | ||||
|  | ||||
| import androidx.activity.compose.BackHandler | ||||
| import androidx.compose.foundation.layout.PaddingValues | ||||
| import androidx.compose.foundation.layout.padding | ||||
| import androidx.compose.foundation.lazy.LazyListState | ||||
| import androidx.compose.foundation.lazy.items | ||||
| import androidx.compose.foundation.lazy.rememberLazyListState | ||||
| import androidx.compose.material.icons.Icons | ||||
| import androidx.compose.material.icons.automirrored.outlined.ArrowForward | ||||
| import androidx.compose.material3.Icon | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.runtime.LaunchedEffect | ||||
| import androidx.compose.runtime.collectAsState | ||||
| import androidx.compose.runtime.getValue | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.platform.LocalContext | ||||
| import cafe.adriel.voyager.core.model.rememberScreenModel | ||||
| import cafe.adriel.voyager.navigator.LocalNavigator | ||||
| import cafe.adriel.voyager.navigator.currentOrThrow | ||||
| import eu.kanade.presentation.browse.MigrateMangaScreen | ||||
| import eu.kanade.presentation.components.AppBar | ||||
| import eu.kanade.presentation.manga.components.BaseMangaListItem | ||||
| import eu.kanade.presentation.util.Screen | ||||
| import eu.kanade.tachiyomi.ui.manga.MangaScreen | ||||
| import eu.kanade.tachiyomi.util.system.toast | ||||
| import kotlinx.coroutines.flow.collectLatest | ||||
| import mihon.feature.migration.config.MigrationConfigScreen | ||||
| import tachiyomi.domain.manga.model.Manga | ||||
| import tachiyomi.i18n.MR | ||||
| import tachiyomi.presentation.core.components.FastScrollLazyColumn | ||||
| import tachiyomi.presentation.core.components.material.ExtendedFloatingActionButton | ||||
| import tachiyomi.presentation.core.components.material.Scaffold | ||||
| import tachiyomi.presentation.core.i18n.stringResource | ||||
| import tachiyomi.presentation.core.screens.EmptyScreen | ||||
| import tachiyomi.presentation.core.screens.LoadingScreen | ||||
| import tachiyomi.presentation.core.util.selectedBackground | ||||
| import tachiyomi.presentation.core.util.shouldExpandFAB | ||||
|  | ||||
| data class MigrateMangaScreen( | ||||
|     private val sourceId: Long, | ||||
| @@ -34,13 +54,59 @@ data class MigrateMangaScreen( | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         MigrateMangaScreen( | ||||
|             navigateUp = navigator::pop, | ||||
|             title = state.source!!.name, | ||||
|             state = state, | ||||
|             onClickItem = { navigator.push(MigrationConfigScreen(it.id)) }, | ||||
|             onClickCover = { navigator.push(MangaScreen(it.id)) }, | ||||
|         ) | ||||
|         BackHandler(enabled = state.selectionMode) { | ||||
|             screenModel.clearSelection() | ||||
|         } | ||||
|  | ||||
|         val lazyListState = rememberLazyListState() | ||||
|  | ||||
|         Scaffold( | ||||
|             topBar = { scrollBehavior -> | ||||
|                 AppBar( | ||||
|                     title = state.source!!.name, | ||||
|                     navigateUp = { | ||||
|                         if (state.selectionMode) { | ||||
|                             screenModel.clearSelection() | ||||
|                         } else { | ||||
|                             navigator.pop() | ||||
|                         } | ||||
|                     }, | ||||
|                     scrollBehavior = scrollBehavior, | ||||
|                 ) | ||||
|             }, | ||||
|             floatingActionButton = { | ||||
|                 if (state.selectionMode) { | ||||
|                     ExtendedFloatingActionButton( | ||||
|                         text = { Text(text = stringResource(MR.strings.migrationConfigScreen_continueButtonText)) }, | ||||
|                         icon = { | ||||
|                             Icon(imageVector = Icons.AutoMirrored.Outlined.ArrowForward, contentDescription = null) | ||||
|                         }, | ||||
|                         onClick = { | ||||
|                             val selection = state.selection | ||||
|                             screenModel.clearSelection() | ||||
|                             navigator.push(MigrationConfigScreen(selection)) | ||||
|                         }, | ||||
|                         expanded = lazyListState.shouldExpandFAB(), | ||||
|                     ) | ||||
|                 } | ||||
|             }, | ||||
|         ) { contentPadding -> | ||||
|             if (state.isEmpty) { | ||||
|                 EmptyScreen( | ||||
|                     stringRes = MR.strings.empty_screen, | ||||
|                     modifier = Modifier.padding(contentPadding), | ||||
|                 ) | ||||
|                 return@Scaffold | ||||
|             } | ||||
|  | ||||
|             MigrateMangaContent( | ||||
|                 lazyListState = lazyListState, | ||||
|                 contentPadding = contentPadding, | ||||
|                 state = state, | ||||
|                 onClickItem = screenModel::toggleSelection, | ||||
|                 onClickCover = { navigator.push(MangaScreen(it.id)) }, | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         LaunchedEffect(Unit) { | ||||
|             screenModel.events.collectLatest { event -> | ||||
| @@ -52,4 +118,43 @@ data class MigrateMangaScreen( | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Composable | ||||
|     private fun MigrateMangaContent( | ||||
|         lazyListState: LazyListState, | ||||
|         contentPadding: PaddingValues, | ||||
|         state: MigrateMangaScreenModel.State, | ||||
|         onClickItem: (Manga) -> Unit, | ||||
|         onClickCover: (Manga) -> Unit, | ||||
|     ) { | ||||
|         FastScrollLazyColumn( | ||||
|             state = lazyListState, | ||||
|             contentPadding = contentPadding, | ||||
|         ) { | ||||
|             items(state.titles) { manga -> | ||||
|                 MigrateMangaItem( | ||||
|                     manga = manga, | ||||
|                     isSelected = manga.id in state.selection, | ||||
|                     onClickItem = onClickItem, | ||||
|                     onClickCover = onClickCover, | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Composable | ||||
|     private fun MigrateMangaItem( | ||||
|         manga: Manga, | ||||
|         isSelected: Boolean, | ||||
|         onClickItem: (Manga) -> Unit, | ||||
|         onClickCover: (Manga) -> Unit, | ||||
|         modifier: Modifier = Modifier, | ||||
|     ) { | ||||
|         BaseMangaListItem( | ||||
|             modifier = modifier.selectedBackground(isSelected), | ||||
|             manga = manga, | ||||
|             onClickItem = { onClickItem(manga) }, | ||||
|             onClickCover = { onClickCover(manga) }, | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.receiveAsFlow | ||||
| import kotlinx.coroutines.flow.update | ||||
| import kotlinx.coroutines.launch | ||||
| import logcat.LogPriority | ||||
| import mihon.core.common.utils.mutate | ||||
| import tachiyomi.core.common.util.system.logcat | ||||
| import tachiyomi.domain.manga.interactor.GetFavorites | ||||
| import tachiyomi.domain.manga.model.Manga | ||||
| @@ -57,9 +58,23 @@ class MigrateMangaScreenModel( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun toggleSelection(item: Manga) { | ||||
|         mutableState.update { state -> | ||||
|             val selection = state.selection.mutate { list -> | ||||
|                 if (!list.remove(item.id)) list.add(item.id) | ||||
|             } | ||||
|             state.copy(selection = selection) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun clearSelection() { | ||||
|         mutableState.update { it.copy(selection = emptySet()) } | ||||
|     } | ||||
|  | ||||
|     @Immutable | ||||
|     data class State( | ||||
|         val source: Source? = null, | ||||
|         val selection: Set<Long> = emptySet(), | ||||
|         private val titleList: ImmutableList<Manga>? = null, | ||||
|     ) { | ||||
|  | ||||
| @@ -71,6 +86,8 @@ class MigrateMangaScreenModel( | ||||
|  | ||||
|         val isEmpty: Boolean | ||||
|             get() = titles.isEmpty() | ||||
|  | ||||
|         val selectionMode = selection.isNotEmpty() | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user