diff --git a/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt b/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt index c3f9502dc..2fa44d3ac 100644 --- a/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt +++ b/UIViews/src/main/java/com/programmersbox/uiviews/notifications/NotificationFragment.kt @@ -298,8 +298,11 @@ fun NotificationsScreen( navController = navController, vm = vm, p = p, + db = db, toSource = { s -> sourceRepository.toSourceByApiServiceName(s)?.apiService }, onLoadingChange = { showLoadingDialog = it }, + deleteNotification = vm::deleteNotification, + cancelNotification = cancelNotification, onError = { scope.launch { state.snackbarHostState.currentSnackbarData?.dismiss() @@ -428,11 +431,14 @@ fun NotificationsScreen( } } -@OptIn(ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable private fun DateSort( navController: NavController, vm: NotificationScreenViewModel, + deleteNotification: (db: ItemDao, item: NotificationItem, block: () -> Unit) -> Unit, + cancelNotification: (NotificationItem) -> Unit, + db: ItemDao, p: PaddingValues, toSource: (String) -> ApiService?, onError: (NotificationItem) -> Unit, @@ -519,33 +525,98 @@ private fun DateSort( modifier = Modifier.fillMaxWidth() ) { it.forEach { i -> - M3CoverCard( - imageUrl = i.imageUrl.orEmpty(), - name = i.notiTitle, - placeHolder = R.drawable.ic_site_settings, - onLongPress = { - newItem(if (it == ComponentState.Pressed) i else null) - showBanner = it == ComponentState.Pressed - }, - onClick = { - toSource(i.source)?.let { source -> - Cached.cache[i.url]?.let { - flow { - emit( - it - .toDbModel() - .toItemModel(source) - ) + var showPopup by remember { mutableStateOf(false) } + + if (showPopup) { + val onDismiss = { showPopup = false } + + AlertDialog( + onDismissRequest = onDismiss, + title = { Text(stringResource(R.string.removeNoti, i.notiTitle)) }, + confirmButton = { + TextButton( + onClick = { + deleteNotification(db, i, onDismiss) + cancelNotification(i) } - } ?: source.getSourceByUrlFlow(i.url) + ) { Text(stringResource(R.string.yes)) } + }, + dismissButton = { TextButton(onClick = onDismiss) { Text(stringResource(R.string.no)) } } + ) + } + + val dismissState = rememberDismissState( + confirmValueChange = { + if (it == DismissValue.DismissedToEnd || it == DismissValue.DismissedToStart) { + showPopup = true } - ?.dispatchIo() - ?.onStart { onLoadingChange(true) } - ?.onEach { - onLoadingChange(false) - navController.navigateToDetails(it) - } - ?.launchIn(scope) ?: onError(i) + false + } + ) + + SwipeToDismiss( + state = dismissState, + modifier = Modifier.weight(1f, false), + background = { + val color by animateColorAsState( + when (dismissState.targetValue) { + DismissValue.Default -> Color.Transparent + DismissValue.DismissedToEnd -> Color.Red + DismissValue.DismissedToStart -> Color.Red + }, label = "" + ) + + val scale by animateFloatAsState( + if (dismissState.targetValue == DismissValue.Default) 0.75f else 1f, + label = "" + ) + + Box( + Modifier + .fillMaxSize() + .clip(MaterialTheme.shapes.medium) + .background(color) + .padding(horizontal = 20.dp), + contentAlignment = Alignment.Center + ) { + Icon( + Icons.Default.Delete, + contentDescription = null, + modifier = Modifier.scale(scale), + tint = M3MaterialTheme.colorScheme.onSurface + ) + } + }, + dismissContent = { + M3CoverCard( + imageUrl = i.imageUrl.orEmpty(), + name = i.notiTitle, + placeHolder = R.drawable.ic_site_settings, + onLongPress = { + newItem(if (it == ComponentState.Pressed) i else null) + showBanner = it == ComponentState.Pressed + }, + onClick = { + toSource(i.source)?.let { source -> + Cached.cache[i.url]?.let { + flow { + emit( + it + .toDbModel() + .toItemModel(source) + ) + } + } ?: source.getSourceByUrlFlow(i.url) + } + ?.dispatchIo() + ?.onStart { onLoadingChange(true) } + ?.onEach { + onLoadingChange(false) + navController.navigateToDetails(it) + } + ?.launchIn(scope) ?: onError(i) + }, + ) } ) } diff --git a/mangaworld/src/main/java/com/programmersbox/mangaworld/reader/ReaderCompose.kt b/mangaworld/src/main/java/com/programmersbox/mangaworld/reader/ReaderCompose.kt index 1fc31f2f0..cbd9e9a07 100644 --- a/mangaworld/src/main/java/com/programmersbox/mangaworld/reader/ReaderCompose.kt +++ b/mangaworld/src/main/java/com/programmersbox/mangaworld/reader/ReaderCompose.kt @@ -15,7 +15,11 @@ import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateDpAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.expandHorizontally +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut import androidx.compose.animation.shrinkHorizontally +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background @@ -73,8 +77,6 @@ import androidx.compose.material.pullrefresh.pullRefresh import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.AlertDialog import androidx.compose.material3.BottomAppBar -import androidx.compose.material3.BottomAppBarDefaults -import androidx.compose.material3.BottomAppBarScrollBehavior import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.CenterAlignedTopAppBar @@ -311,20 +313,7 @@ fun ReadView( val showItems by remember { derivedStateOf { readVm.showInfo || listShowItems || pagerShowItems } } - val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(canScroll = { !showItems }) - val bottomBarScrollBehavior = BottomAppBarDefaults.exitAlwaysScrollBehavior(canScroll = { !showItems }) - - LaunchedEffect(showItems) { - if (showItems) { - //Expand - scrollBehavior.state.heightOffset = 0f - bottomBarScrollBehavior.state.heightOffset = 0f - } else { - //Collapse - scrollBehavior.state.heightOffset = -1000f - bottomBarScrollBehavior.state.heightOffset = -1000f - } - } + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) var showBottomSheet by remember { mutableStateOf(false) } @@ -364,37 +353,34 @@ fun ReadView( gesturesEnabled = readVm.list.size > 1 ) { Scaffold( - modifier = Modifier - .nestedScroll(scrollBehavior.nestedScrollConnection) - .nestedScroll(bottomBarScrollBehavior.nestedScrollConnection), + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), topBar = { - /*AnimatedVisibility( + AnimatedVisibility( visible = showItems, enter = slideInVertically() + fadeIn(), exit = slideOutVertically() + fadeOut() - ) {*/ - TopBar( - scrollBehavior = scrollBehavior, - pages = pages, - currentPage = currentPage, - vm = readVm - ) - //} + ) { + TopBar( + scrollBehavior = scrollBehavior, + pages = pages, + currentPage = currentPage, + vm = readVm + ) + } }, bottomBar = { - /*AnimatedVisibility( + AnimatedVisibility( visible = showItems, enter = slideInVertically { it / 2 } + fadeIn(), exit = slideOutVertically { it / 2 } + fadeOut() - ) {*/ - BottomBar( - onPageSelectClick = { showBottomSheet = true }, - onSettingsClick = { settingsPopup = true }, - chapterChange = ::showToast, - vm = readVm, - scrollBehavior = bottomBarScrollBehavior - ) - //} + ) { + BottomBar( + onPageSelectClick = { showBottomSheet = true }, + onSettingsClick = { settingsPopup = true }, + chapterChange = ::showToast, + vm = readVm + ) + } } ) { paddingValues -> Box( @@ -1082,20 +1068,17 @@ private fun TopBar( ) } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun BottomBar( vm: ReadViewModel, onPageSelectClick: () -> Unit, onSettingsClick: () -> Unit, chapterChange: () -> Unit, - scrollBehavior: BottomAppBarScrollBehavior, modifier: Modifier = Modifier, ) { BottomAppBar( modifier = modifier, - windowInsets = WindowInsets(0.dp), - scrollBehavior = scrollBehavior + windowInsets = WindowInsets(0.dp) ) { val prevShown = vm.currentChapter < vm.list.lastIndex val nextShown = vm.currentChapter > 0