Skip to content

Commit

Permalink
Add fullscreen mode, set safe drawing area, handle taps
Browse files Browse the repository at this point in the history
  • Loading branch information
qnga committed Sep 25, 2024
1 parent 48092d4 commit 0427968
Show file tree
Hide file tree
Showing 31 changed files with 462 additions and 141 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,19 @@ import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import org.readium.navigator.demo.preferences.UserPreferences
import org.readium.navigator.web.PrepaginatedWebNavigator
import org.readium.r2.shared.ExperimentalReadiumApi
import androidx.core.view.WindowCompat
import org.readium.navigator.demo.util.Fullscreenable
import org.readium.r2.shared.util.toAbsoluteUrl

@OptIn(ExperimentalReadiumApi::class, ExperimentalMaterial3Api::class)
class DemoActivity : ComponentActivity() {

private val viewModel: DemoViewModel by viewModels()
Expand All @@ -56,90 +37,55 @@ class DemoActivity : ComponentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()

setContent {
MaterialTheme {
val snackbarHostState = remember { SnackbarHostState() }
val preferencesSheetState = rememberModalBottomSheetState()
var showPreferences by remember { mutableStateOf(false) }
val fullscreenState = remember { mutableStateOf(false) }

Scaffold(
modifier = Modifier
.safeDrawingPadding()
.fillMaxSize(),
topBar = {
TopBar(
onPreferencesActivated = {
showPreferences = !showPreferences
}
)
},
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
) { paddingValues ->
Fullscreenable(
fullscreenState = fullscreenState,
insetsController = WindowCompat.getInsetsController(window, window.decorView)
) {
val snackbarHostState = remember { SnackbarHostState() }
val state = viewModel.state.collectAsState()

Box(
modifier = Modifier
.padding(paddingValues)
.fillMaxSize(),
propagateMinConstraints = true
) {
val state = viewModel.state.collectAsState()
LaunchedEffect(state.value) {
fullscreenState.value = when (state.value) {
DemoViewModel.State.BookSelection -> true
is DemoViewModel.State.Error -> false
DemoViewModel.State.Loading -> true
is DemoViewModel.State.Reader -> true
}
}

when (val stateNow = state.value) {
DemoViewModel.State.BookSelection -> {
when (val stateNow = state.value) {
DemoViewModel.State.BookSelection -> {
LaunchedEffect(stateNow) {
sharedStoragePickerLauncher.launch(arrayOf("*/*"))
}
is DemoViewModel.State.Error -> {
LaunchedEffect(stateNow.error) {
snackbarHostState.showSnackbar(stateNow.error.message)
viewModel.acknowledgeError()
}
}
DemoViewModel.State.Loading -> {
// Display nothing
}
is DemoViewModel.State.Reader -> {
if (showPreferences) {
ModalBottomSheet(
sheetState = preferencesSheetState,
onDismissRequest = { showPreferences = false }
) {
UserPreferences(
model = stateNow.preferencesViewModel,
title = "Preferences"
)
}
}
}

PrepaginatedWebNavigator(
modifier = Modifier
.fillMaxSize(),
state = stateNow.navigatorState
)
is DemoViewModel.State.Error -> {
LaunchedEffect(stateNow.error) {
snackbarHostState.showSnackbar(stateNow.error.message)
viewModel.acknowledgeError()
}
}

DemoViewModel.State.Loading -> {
// Display and do nothing
}

is DemoViewModel.State.Reader -> {
Reader(
state = stateNow,
fullScreenState = fullscreenState
)
}
}
}
}
}
}

@Composable
private fun TopBar(
onPreferencesActivated: () -> Unit
) {
CenterAlignedTopAppBar(
title = {},
actions = {
IconButton(
onClick = onPreferencesActivated
) {
Icon(
imageVector = Icons.Filled.Settings,
contentDescription = "Preferences"
)
}
}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2024 Readium Foundation. All rights reserved.
* Use of this source code is governed by the BSD-style license
* available in the top-level LICENSE file of the project.
*/

package org.readium.navigator.demo

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.zIndex
import org.readium.navigator.demo.preferences.UserPreferences
import org.readium.navigator.web.PrepaginatedWebNavigator
import org.readium.r2.shared.ExperimentalReadiumApi

@OptIn(ExperimentalMaterial3Api::class, ExperimentalReadiumApi::class)
@Composable
fun Reader(
state: DemoViewModel.State.Reader,
fullScreenState: MutableState<Boolean>
) {
val showPreferences = remember { mutableStateOf(false) }
val preferencesSheetState = rememberModalBottomSheetState()

if (showPreferences.value) {
ModalBottomSheet(
sheetState = preferencesSheetState,
onDismissRequest = { showPreferences.value = false }
) {
UserPreferences(
model = state.preferencesViewModel,
title = "Preferences"
)
}
}

Box {
TopBar(
modifier = Modifier.zIndex(1f),
visible = !fullScreenState.value,
onPreferencesActivated = { showPreferences.value = !showPreferences.value }
)

PrepaginatedWebNavigator(
modifier = Modifier.fillMaxSize(),
state = state.navigatorState,
onTap = { fullScreenState.value = !fullScreenState.value; true }
)
}
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun TopBar(
modifier: Modifier,
visible: Boolean,
onPreferencesActivated: () -> Unit
) {
AnimatedVisibility(
modifier = modifier,
visible = visible,
enter = fadeIn(),
exit = fadeOut()
) {
TopAppBar(
title = {},
actions = {
IconButton(
onClick = onPreferencesActivated
) {
Icon(
imageVector = Icons.Filled.Settings,
contentDescription = "Preferences"
)
}
}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.readium.navigator.demo.util

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat

@Composable
fun Fullscreenable(
fullscreenState: State<Boolean>,
insetsController: WindowInsetsControllerCompat,
content: @Composable () -> Unit
) {
insetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE

LaunchedEffect(fullscreenState.value) {
if (fullscreenState.value) {
insetsController.hide(WindowInsetsCompat.Type.systemBars())
} else {
insetsController.show(WindowInsetsCompat.Type.systemBars())
}
}

content.invoke()
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0427968

Please sign in to comment.