Skip to content

Commit

Permalink
- Feat: Add User Gesture Setting for Reader Chapter List
Browse files Browse the repository at this point in the history
This commit introduces a new setting that allows users to enable or disable user gestures for navigating the chapter list within the reader.

- A toggle switch is added to the Reader Settings menu to control this setting.
- When enabled, users can swipe to navigate the chapter list.
- When disabled, swipe gestures are ignored, and users must tap on a chapter to change it.
  • Loading branch information
jacobrein committed Oct 21, 2024
1 parent 298bd3a commit 97af2d2
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.offset
Expand Down Expand Up @@ -67,7 +68,6 @@ class MultipleBarState(
}
}

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun BoxScope.MultipleActions(
state: MultipleBarState,
Expand All @@ -79,49 +79,66 @@ fun BoxScope.MultipleActions(
) {
val scope = rememberCoroutineScope()
if (middleNavItem == MiddleNavigationAction.Multiple) {
AnimatedVisibility(
visible = state.showHorizontalBar,
enter = slideInVertically(
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec()
) { it / 2 } + fadeIn(
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec()
),
exit = slideOutVertically(
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec()
) { it / 2 } + fadeOut(
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec()
),
MultipleActions(
state = state,
leadingContent = {
multipleActions.startAction.item?.ScreenBottomItem(
currentDestination = currentDestination,
navController = navController,
additionalOnClick = { scope.launch { if (state.hideOnClick) state.hide() } }
)
},
trailingContent = {
multipleActions.endAction.item?.ScreenBottomItem(
currentDestination = currentDestination,
navController = navController,
additionalOnClick = { scope.launch { if (state.hideOnClick) state.hide() } }
)
},
modifier = modifier
.align(Alignment.BottomCenter)
.windowInsetsPadding(WindowInsets.navigationBars)
.offset(y = -FloatingAppBarDefaults.ScreenOffset),
)
}
}

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun BoxScope.MultipleActions(
state: MultipleBarState,
leadingContent: @Composable RowScope.() -> Unit,
trailingContent: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
) {
val scope = rememberCoroutineScope()
AnimatedVisibility(
visible = state.showHorizontalBar,
enter = slideInVertically(
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec()
) { it / 2 } + fadeIn(
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec()
),
exit = slideOutVertically(
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec()
) { it / 2 } + fadeOut(
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec()
),
modifier = modifier
.align(Alignment.BottomCenter)
.windowInsetsPadding(WindowInsets.navigationBars)
.offset(y = -FloatingAppBarDefaults.ScreenOffset),
) {
HorizontalFloatingAppBar(
expanded = state.expanded,
leadingContent = leadingContent,
trailingContent = trailingContent,
) {
HorizontalFloatingAppBar(
expanded = state.expanded,
leadingContent = {
multipleActions.startAction.item?.ScreenBottomItem(
currentDestination = currentDestination,
navController = navController,
additionalOnClick = { scope.launch { if (state.hideOnClick) state.hide() } }
)
},
trailingContent = {
multipleActions.endAction.item?.ScreenBottomItem(
currentDestination = currentDestination,
navController = navController,
additionalOnClick = { scope.launch { if (state.hideOnClick) state.hide() } }
)
},
FilledIconButton(
modifier = Modifier.width(64.dp),
onClick = { scope.launch { state.hide() } }
) {
FilledIconButton(
modifier = Modifier.width(64.dp),
onClick = { scope.launch { state.hide() } }
) {
Icon(
if (state.expanded) Icons.Default.UnfoldLess else Icons.Filled.UnfoldMore,
contentDescription = "Localized description"
)
}
Icon(
if (state.expanded) Icons.Default.UnfoldLess else Icons.Filled.UnfoldMore,
contentDescription = "Localized description"
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.LibraryBooks
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material.icons.filled.FavoriteBorder
import androidx.compose.material.icons.filled.Gesture
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -71,6 +74,7 @@ import com.programmersbox.uiviews.utils.M3CoverCard
import com.programmersbox.uiviews.utils.M3PlaceHolderCoverCard
import com.programmersbox.uiviews.utils.NotificationLogo
import com.programmersbox.uiviews.utils.PreferenceSetting
import com.programmersbox.uiviews.utils.SwitchSetting
import com.programmersbox.uiviews.utils.adaptiveGridCell
import com.programmersbox.uiviews.utils.dispatchIo
import kotlinx.coroutines.GlobalScope
Expand Down Expand Up @@ -373,6 +377,14 @@ class GenericManga(
mangaSettingsHandling = mangaSettingsHandling,
onImageLoaderClick = { navController.navigate(ImageLoaderSettingsRoute) { launchSingleTop = true } }
)

var userGestureAllowed by mangaSettingsHandling.rememberUserGestureEnabled()
SwitchSetting(
value = userGestureAllowed,
updateValue = { userGestureAllowed = it },
settingTitle = { Text("Allow User Gestures for Chapter List in Reader") },
settingIcon = { Icon(Icons.Default.Gesture, null, modifier = Modifier.fillMaxSize()) }
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ class MangaSettingsHandling(context: Context) {
defaultValue = ImageLoaderType.Kamel
)

@Composable
fun rememberUserGestureEnabled() = preferences.rememberPreference(
key = { it.allowUserDrawerGesture },
update = { setAllowUserDrawerGesture(it) },
defaultValue = true
)

inner class SettingInfo<T>(
val flow: Flow<T>,
private val updateValue: suspend MangaSettings.Builder.(T) -> MangaSettings.Builder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.GridOn
import androidx.compose.material.icons.filled.Numbers
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.BottomAppBarDefaults
Expand Down Expand Up @@ -177,6 +178,7 @@ internal fun BottomBar(
onPageSelectClick: () -> Unit,
onSettingsClick: () -> Unit,
chapterChange: () -> Unit,
onChapterShow: () -> Unit,
showBlur: Boolean,
isAmoledMode: Boolean,
modifier: Modifier = Modifier,
Expand Down Expand Up @@ -252,6 +254,11 @@ internal fun BottomBar(
modifier = Modifier.weight(1f)
) { Icon(Icons.Default.GridOn, null) }

IconButton(
onClick = onChapterShow,
modifier = Modifier.weight(1f)
) { Icon(Icons.Default.Numbers, null) }

IconButton(
onClick = onSettingsClick,
modifier = Modifier.weight(1f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import androidx.compose.foundation.pager.VerticalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.ModalDrawerSheet
Expand Down Expand Up @@ -78,7 +79,7 @@ import eu.wewox.pagecurl.page.rememberPageCurlState
import kotlinx.coroutines.launch
import org.koin.compose.koinInject

@OptIn(ExperimentalPageCurlApi::class)
@OptIn(ExperimentalPageCurlApi::class, ExperimentalMaterial3ExpressiveApi::class)
@ExperimentalMaterial3Api
@ExperimentalComposeUiApi
@ExperimentalAnimationApi
Expand Down Expand Up @@ -115,6 +116,8 @@ fun ReadView(

var readerType by mangaSettingsHandling.rememberReaderType()

val userGestureAllowed by mangaSettingsHandling.rememberUserGestureEnabled()

val pagerState = rememberPagerState(
initialPage = 0,
initialPageOffsetFraction = 0f
Expand Down Expand Up @@ -234,7 +237,6 @@ fun ReadView(
}

val hazeState = remember { HazeState() }
val background = MaterialTheme.colorScheme.background

ModalNavigationDrawer(
drawerState = drawerState,
Expand All @@ -246,7 +248,7 @@ fun ReadView(
)
}
},
gesturesEnabled = readVm.list.size > 1
gesturesEnabled = (readVm.list.size > 1 && userGestureAllowed) || drawerState.isOpen
) {
Scaffold(
topBar = {
Expand Down Expand Up @@ -281,6 +283,7 @@ fun ReadView(
onPageSelectClick = { showBottomSheet = true },
onSettingsClick = { settingsPopup = true },
chapterChange = ::showToast,
onChapterShow = { scope.launch { drawerState.open() } },
vm = readVm,
showBlur = showBlur,
isAmoledMode = isAmoledMode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.material.icons.filled.BatteryAlert
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.FormatLineSpacing
import androidx.compose.material.icons.filled.Gesture
import androidx.compose.material.icons.filled.Image
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.DropdownMenu
Expand Down Expand Up @@ -68,6 +69,7 @@ import com.programmersbox.uiviews.utils.LocalSettingsHandling
import com.programmersbox.uiviews.utils.PreferenceSetting
import com.programmersbox.uiviews.utils.SettingsHandling
import com.programmersbox.uiviews.utils.ShowWhen
import com.programmersbox.uiviews.utils.SwitchSetting
import com.programmersbox.uiviews.utils.adaptiveGridCell
import io.kamel.image.KamelImage
import io.kamel.image.asyncPainterResource
Expand Down Expand Up @@ -130,6 +132,17 @@ internal fun SettingsSheet(
range = 0f..10f
)
HorizontalDivider()

var userGestureAllowed by mangaSettingsHandling.rememberUserGestureEnabled()
SwitchSetting(
value = userGestureAllowed,
updateValue = { userGestureAllowed = it },
settingTitle = { Text("Allow User Gestures for Chapter List in Reader") },
settingIcon = { Icon(Icons.Default.Gesture, null, modifier = Modifier.fillMaxSize()) }
)

HorizontalDivider()

var showReaderTypeDropdown by remember { mutableStateOf(false) }

PreferenceSetting(
Expand Down
1 change: 1 addition & 0 deletions mangaworld/src/main/proto/manga_settings.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ message MangaSettings {
ReaderType readerType = 5;
ImageLoaderType imageLoaderType = 6;
bool useFlipPager = 7;
bool allowUserDrawerGesture = 8;
}

enum PlayingStartAction {
Expand Down

0 comments on commit 97af2d2

Please sign in to comment.