Navigation bars
This commit is contained in:
@@ -92,9 +92,12 @@ dependencies {
|
||||
implementation 'androidx.compose.material:material-icons-extended'
|
||||
implementation 'androidx.activity:activity-compose:1.8.2'
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.7.0'
|
||||
implementation "com.google.accompanist:accompanist-adaptive:0.34.0"
|
||||
implementation "androidx.navigation:navigation-compose:2.7.7"
|
||||
|
||||
kapt 'androidx.lifecycle:lifecycle-compiler:2.7.0'
|
||||
|
||||
implementation "androidx.paging:paging-compose:3.2.1"
|
||||
|
||||
implementation "io.ktor:ktor-client-core:2.3.8"
|
||||
|
||||
@@ -24,8 +24,10 @@ import androidx.activity.enableEdgeToEdge
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
|
||||
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.google.accompanist.adaptive.calculateDisplayFeatures
|
||||
import xyz.quaver.pupil.ui.composable.PupilApp
|
||||
import xyz.quaver.pupil.ui.composable.MainApp
|
||||
import xyz.quaver.pupil.ui.theme.AppTheme
|
||||
import xyz.quaver.pupil.ui.viewmodel.MainViewModel
|
||||
|
||||
@@ -42,10 +44,13 @@ class MainActivity : BaseActivity() {
|
||||
val windowSize = calculateWindowSizeClass(this)
|
||||
val displayFeatures = calculateDisplayFeatures(this)
|
||||
|
||||
PupilApp(
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
MainApp(
|
||||
windowSize = windowSize,
|
||||
displayFeatures = displayFeatures,
|
||||
uiState = viewModel.uiState
|
||||
uiState = uiState,
|
||||
navigateToDestination = viewModel::navigateToDestination
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package xyz.quaver.pupil.ui.composable
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
@Composable
|
||||
fun GalleryList(
|
||||
|
||||
) {
|
||||
|
||||
}
|
||||
@@ -1,6 +1,14 @@
|
||||
package xyz.quaver.pupil.ui.composable
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.DrawerValue
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalNavigationDrawer
|
||||
import androidx.compose.material3.PermanentNavigationDrawer
|
||||
import androidx.compose.material3.rememberDrawerState
|
||||
import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
|
||||
@@ -8,16 +16,18 @@ import androidx.compose.material3.windowsizeclass.WindowSizeClass
|
||||
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.window.layout.DisplayFeature
|
||||
import androidx.window.layout.FoldingFeature
|
||||
import kotlinx.coroutines.launch
|
||||
import xyz.quaver.pupil.ui.viewmodel.MainUIState
|
||||
|
||||
@Composable
|
||||
fun PupilApp(
|
||||
fun MainApp(
|
||||
windowSize: WindowSizeClass,
|
||||
displayFeatures: List<DisplayFeature>,
|
||||
uiState: MainUIState
|
||||
uiState: MainUIState,
|
||||
navigateToDestination: (MainDestination) -> Unit
|
||||
) {
|
||||
val navigationType: NavigationType
|
||||
val contentType: ContentType
|
||||
@@ -31,7 +41,7 @@ fun PupilApp(
|
||||
|
||||
when (windowSize.widthSizeClass) {
|
||||
WindowWidthSizeClass.Compact -> {
|
||||
navigationType = NavigationType.NAVIGATION_RAIL
|
||||
navigationType = NavigationType.BOTTOM_NAVIGATION
|
||||
contentType = ContentType.SINGLE_PANE
|
||||
}
|
||||
WindowWidthSizeClass.Medium -> {
|
||||
@@ -51,7 +61,7 @@ fun PupilApp(
|
||||
contentType = ContentType.DUAL_PANE
|
||||
}
|
||||
else -> {
|
||||
navigationType = NavigationType.NAVIGATION_RAIL
|
||||
navigationType = NavigationType.BOTTOM_NAVIGATION
|
||||
contentType = ContentType.SINGLE_PANE
|
||||
}
|
||||
}
|
||||
@@ -63,30 +73,113 @@ fun PupilApp(
|
||||
else -> NavigationContentPosition.TOP
|
||||
}
|
||||
|
||||
PupilNavigationWrapper(
|
||||
MainNavigationWrapper(
|
||||
navigationType,
|
||||
contentType,
|
||||
navigationContentPosition
|
||||
displayFeatures,
|
||||
navigationContentPosition,
|
||||
uiState,
|
||||
navigateToDestination
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PupilNavigationWrapper(
|
||||
private fun MainNavigationWrapper(
|
||||
navigationType: NavigationType,
|
||||
contentType: ContentType,
|
||||
navigationContentPosition: NavigationContentPosition
|
||||
displayFeatures: List<DisplayFeature>,
|
||||
navigationContentPosition: NavigationContentPosition,
|
||||
uiState: MainUIState,
|
||||
navigateToDestination: (MainDestination) -> Unit
|
||||
) {
|
||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val openDrawer: () -> Unit = {
|
||||
coroutineScope.launch {
|
||||
drawerState.open()
|
||||
}
|
||||
}
|
||||
|
||||
if (navigationType == NavigationType.PERMANENT_NAVIGATION_DRAWER) {
|
||||
PermanentNavigationDrawer(drawerContent = {
|
||||
PermanentNavigationDrawerContent(
|
||||
navigationContentPosition = navigationContentPosition
|
||||
selectedDestination = uiState.currentDestination,
|
||||
navigationContentPosition = navigationContentPosition,
|
||||
navigateToDestination = navigateToDestination
|
||||
)
|
||||
}) {
|
||||
// PupilMain()
|
||||
MainContent(
|
||||
navigationType = navigationType,
|
||||
contentType = contentType,
|
||||
displayFeatures = displayFeatures,
|
||||
navigationContentPosition = navigationContentPosition,
|
||||
uiState = uiState,
|
||||
navigateToDestination = navigateToDestination,
|
||||
onDrawerClicked = openDrawer
|
||||
)
|
||||
}
|
||||
} else {
|
||||
ModalNavigationDrawer(
|
||||
drawerContent = {
|
||||
ModalNavigationDrawerContent(
|
||||
selectedDestination = uiState.currentDestination,
|
||||
navigationContentPosition = navigationContentPosition,
|
||||
navigateToDestination = navigateToDestination,
|
||||
onDrawerClicked = {
|
||||
coroutineScope.launch {
|
||||
drawerState.close()
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
drawerState = drawerState
|
||||
) {
|
||||
MainContent(
|
||||
navigationType = navigationType,
|
||||
contentType = contentType,
|
||||
displayFeatures = displayFeatures,
|
||||
navigationContentPosition = navigationContentPosition,
|
||||
uiState = uiState,
|
||||
navigateToDestination = navigateToDestination,
|
||||
onDrawerClicked = openDrawer
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MainContent(
|
||||
navigationType: NavigationType,
|
||||
contentType: ContentType,
|
||||
displayFeatures: List<DisplayFeature>,
|
||||
navigationContentPosition: NavigationContentPosition,
|
||||
uiState: MainUIState,
|
||||
navigateToDestination: (MainDestination) -> Unit,
|
||||
onDrawerClicked: () -> Unit
|
||||
) {
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
AnimatedVisibility(visible = navigationType == NavigationType.NAVIGATION_RAIL) {
|
||||
MainNavigationRail(
|
||||
selectedDestination = uiState.currentDestination,
|
||||
navigationContentPosition = navigationContentPosition,
|
||||
navigateToDestination = navigateToDestination,
|
||||
onDrawerClicked = onDrawerClicked
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.inverseOnSurface)
|
||||
) {
|
||||
Box(modifier = Modifier.weight(1f))
|
||||
AnimatedVisibility(visible = navigationType == NavigationType.BOTTOM_NAVIGATION) {
|
||||
BottomNavigationBar(
|
||||
selectedDestination = uiState.currentDestination,
|
||||
navigateToDestination = navigateToDestination
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,37 +2,46 @@ package xyz.quaver.pupil.ui.composable
|
||||
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Download
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material.icons.filled.History
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.Star
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import xyz.quaver.pupil.R
|
||||
|
||||
data class MainDestination(
|
||||
val route: String,
|
||||
val icon: ImageVector,
|
||||
sealed interface MainDestination {
|
||||
val route: String
|
||||
val icon: ImageVector
|
||||
val textId: Int
|
||||
)
|
||||
|
||||
object Search: MainDestination {
|
||||
override val route = "search"
|
||||
override val icon = Icons.Default.Search
|
||||
override val textId = R.string.main_destination_search
|
||||
}
|
||||
|
||||
object History: MainDestination {
|
||||
override val route = "history"
|
||||
override val icon = Icons.Default.History
|
||||
override val textId = R.string.main_destination_history
|
||||
}
|
||||
|
||||
object Downloads: MainDestination {
|
||||
override val route = "downloads"
|
||||
override val icon = Icons.Default.Download
|
||||
override val textId = R.string.main_destination_downloads
|
||||
}
|
||||
|
||||
object Favorites: MainDestination {
|
||||
override val route = "favorites"
|
||||
override val icon = Icons.Default.Favorite
|
||||
override val textId = R.string.main_destination_favorites
|
||||
}
|
||||
}
|
||||
|
||||
val mainDestinations = listOf(
|
||||
MainDestination(
|
||||
"search",
|
||||
Icons.Default.Search,
|
||||
R.string.main_destination_search
|
||||
),
|
||||
MainDestination(
|
||||
"history",
|
||||
Icons.Default.History,
|
||||
R.string.main_destination_history
|
||||
),
|
||||
MainDestination(
|
||||
"downloads",
|
||||
Icons.Default.Download,
|
||||
R.string.main_destination_downloads
|
||||
),
|
||||
MainDestination(
|
||||
"favorites",
|
||||
Icons.Default.Star,
|
||||
R.string.main_destination_favorites
|
||||
),
|
||||
MainDestination.Search,
|
||||
MainDestination.History,
|
||||
MainDestination.Downloads,
|
||||
MainDestination.Favorites
|
||||
)
|
||||
@@ -4,56 +4,289 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.MenuOpen
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material.icons.filled.MenuOpen
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalDrawerSheet
|
||||
import androidx.compose.material3.NavigationBar
|
||||
import androidx.compose.material3.NavigationBarItem
|
||||
import androidx.compose.material3.NavigationDrawerItem
|
||||
import androidx.compose.material3.NavigationDrawerItemDefaults
|
||||
import androidx.compose.material3.NavigationRail
|
||||
import androidx.compose.material3.NavigationRailItem
|
||||
import androidx.compose.material3.PermanentDrawerSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.layout.Measurable
|
||||
import androidx.compose.ui.layout.MeasurePolicy
|
||||
import androidx.compose.ui.layout.layout
|
||||
import androidx.compose.ui.layout.layoutId
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.offset
|
||||
import xyz.quaver.pupil.R
|
||||
|
||||
@Composable
|
||||
fun PermanentNavigationDrawerContent(
|
||||
navigationContentPosition: NavigationContentPosition
|
||||
selectedDestination: MainDestination,
|
||||
navigationContentPosition: NavigationContentPosition,
|
||||
navigateToDestination: (MainDestination) -> Unit
|
||||
) {
|
||||
PermanentDrawerSheet(
|
||||
modifier = Modifier.sizeIn(minWidth = 200.dp, maxWidth = 300.dp),
|
||||
drawerContainerColor = MaterialTheme.colorScheme.inverseOnSurface
|
||||
) {
|
||||
Column(
|
||||
Layout(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.inverseOnSurface)
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
.padding(16.dp),
|
||||
content = {
|
||||
Row(
|
||||
modifier = Modifier.layoutId(LayoutType.HEADER),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(32.dp),
|
||||
painter = painterResource(R.drawable.app_icon),
|
||||
tint = Color.Unspecified,
|
||||
contentDescription = "app icon"
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
text = "Pupil",
|
||||
style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold),
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.layoutId(LayoutType.CONTENT)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
mainDestinations.forEach { destination ->
|
||||
NavigationDrawerItem(
|
||||
label = {
|
||||
Text(
|
||||
text = stringResource(destination.textId),
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = destination.icon,
|
||||
contentDescription = stringResource(destination.textId)
|
||||
)
|
||||
},
|
||||
selected = selectedDestination.route == destination.route,
|
||||
colors = NavigationDrawerItemDefaults.colors(
|
||||
unselectedContainerColor = Color.Transparent
|
||||
),
|
||||
onClick = { navigateToDestination(destination) }
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
measurePolicy = navigationMeasurePolicy(navigationContentPosition)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ModalNavigationDrawerContent(
|
||||
selectedDestination: MainDestination,
|
||||
navigationContentPosition: NavigationContentPosition,
|
||||
navigateToDestination: (MainDestination) -> Unit,
|
||||
onDrawerClicked: () -> Unit
|
||||
) {
|
||||
ModalDrawerSheet {
|
||||
Layout(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.inverseOnSurface)
|
||||
.padding(16.dp),
|
||||
content = {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.layoutId(LayoutType.HEADER)
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(32.dp),
|
||||
painter = painterResource(R.drawable.app_icon),
|
||||
tint = Color.Unspecified,
|
||||
contentDescription = "app icon"
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
text = "Pupil",
|
||||
style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold),
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(onClick = onDrawerClicked) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Default.MenuOpen,
|
||||
contentDescription = stringResource(R.string.main_open_navigation_drawer)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column (
|
||||
modifier = Modifier
|
||||
.layoutId(LayoutType.CONTENT)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
mainDestinations.forEach { destination ->
|
||||
NavigationDrawerItem(
|
||||
label = {
|
||||
Text(
|
||||
text = stringResource(destination.textId),
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
},
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = destination.icon,
|
||||
contentDescription = stringResource(destination.textId)
|
||||
)
|
||||
},
|
||||
selected = selectedDestination.route == destination.route,
|
||||
colors = NavigationDrawerItemDefaults.colors(
|
||||
unselectedContainerColor = Color.Transparent
|
||||
),
|
||||
onClick = { navigateToDestination(destination) }
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
measurePolicy = navigationMeasurePolicy(navigationContentPosition)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MainNavigationRail(
|
||||
selectedDestination: MainDestination,
|
||||
navigationContentPosition: NavigationContentPosition,
|
||||
navigateToDestination: (MainDestination) -> Unit,
|
||||
onDrawerClicked: () -> Unit
|
||||
) {
|
||||
NavigationRail (
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
containerColor = MaterialTheme.colorScheme.inverseOnSurface
|
||||
) {
|
||||
NavigationRailItem(
|
||||
selected = false,
|
||||
onClick = onDrawerClicked,
|
||||
icon = {
|
||||
Icon(
|
||||
modifier = Modifier.size(32.dp),
|
||||
painter = painterResource(R.drawable.app_icon),
|
||||
tint = Color.Unspecified,
|
||||
contentDescription = "app icon"
|
||||
imageVector = Icons.Default.Menu,
|
||||
contentDescription = stringResource(R.string.main_open_navigation_drawer)
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
text = "Pupil",
|
||||
style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold),
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
}
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState()),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
||||
) {
|
||||
mainDestinations.forEach { destination ->
|
||||
NavigationRailItem(
|
||||
selected = selectedDestination.route == destination.route,
|
||||
onClick = { navigateToDestination(destination) },
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = destination.icon,
|
||||
contentDescription = stringResource(destination.textId)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
Column(
|
||||
}
|
||||
}
|
||||
|
||||
) {
|
||||
Text("Help")
|
||||
@Composable
|
||||
fun BottomNavigationBar(
|
||||
selectedDestination: MainDestination,
|
||||
navigateToDestination: (MainDestination) -> Unit
|
||||
) {
|
||||
NavigationBar(modifier = Modifier.fillMaxWidth()) {
|
||||
mainDestinations.forEach { destination ->
|
||||
NavigationBarItem(
|
||||
selected = selectedDestination.route == destination.route,
|
||||
onClick = { navigateToDestination(destination) },
|
||||
icon = {
|
||||
Icon(
|
||||
imageVector = destination.icon,
|
||||
contentDescription = stringResource(destination.textId)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun navigationMeasurePolicy(
|
||||
navigationContentPosition: NavigationContentPosition,
|
||||
): MeasurePolicy {
|
||||
return MeasurePolicy { measurables, constraints ->
|
||||
lateinit var headerMeasurable: Measurable
|
||||
lateinit var contentMeasurable: Measurable
|
||||
measurables.forEach {
|
||||
when (it.layoutId) {
|
||||
LayoutType.HEADER -> headerMeasurable = it
|
||||
LayoutType.CONTENT -> contentMeasurable = it
|
||||
else -> error("Unknown layoutId encountered!")
|
||||
}
|
||||
}
|
||||
|
||||
val headerPlaceable = headerMeasurable.measure(constraints)
|
||||
val contentPlaceable = contentMeasurable.measure(
|
||||
constraints.offset(vertical = -headerPlaceable.height)
|
||||
)
|
||||
layout(constraints.maxWidth, constraints.maxHeight) {
|
||||
headerPlaceable.placeRelative(0, 0)
|
||||
|
||||
val nonContentVerticalSpace = constraints.maxHeight - contentPlaceable.height
|
||||
|
||||
val contentPlaceableY = when (navigationContentPosition) {
|
||||
NavigationContentPosition.TOP -> 0
|
||||
NavigationContentPosition.CENTER -> nonContentVerticalSpace / 2
|
||||
}.coerceAtLeast(headerPlaceable.height)
|
||||
|
||||
contentPlaceable.placeRelative(0, contentPlaceableY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class LayoutType {
|
||||
HEADER, CONTENT
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package xyz.quaver.pupil.ui.composable
|
||||
|
||||
enum class NavigationType {
|
||||
NAVIGATION_RAIL, PERMANENT_NAVIGATION_DRAWER
|
||||
NAVIGATION_RAIL, PERMANENT_NAVIGATION_DRAWER, BOTTOM_NAVIGATION
|
||||
}
|
||||
@@ -1,14 +1,25 @@
|
||||
package xyz.quaver.pupil.ui.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import xyz.quaver.pupil.networking.SearchQuery
|
||||
import xyz.quaver.pupil.ui.composable.MainRoutes
|
||||
import xyz.quaver.pupil.ui.composable.MainDestination
|
||||
import xyz.quaver.pupil.ui.composable.mainDestinations
|
||||
|
||||
class MainViewModel : ViewModel() {
|
||||
val uiState: MainUIState = MainUIState()
|
||||
private val _uiState = MutableStateFlow(MainUIState())
|
||||
val uiState: StateFlow<MainUIState> = _uiState
|
||||
|
||||
fun navigateToDestination(destination: MainDestination) {
|
||||
_uiState.value = MainUIState(
|
||||
currentDestination = destination
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class MainUIState(
|
||||
val route: MainRoutes = MainRoutes.SEARCH,
|
||||
val query: SearchQuery? = null
|
||||
val currentDestination: MainDestination = mainDestinations.first(),
|
||||
val query: SearchQuery? = null,
|
||||
val loading: Boolean = true
|
||||
)
|
||||
@@ -33,6 +33,7 @@
|
||||
<string name="default_query_dialog_filter_guro">グロフィルター</string>
|
||||
<string name="default_query_dialog_language">"言語: "</string>
|
||||
<string name="default_query_dialog_title">デフォルトキーワード設定</string>
|
||||
<string name="main_open_navigation_drawer">メニューを開く</string>
|
||||
<string name="main_drawer_group_contact_title">お問い合わせ先</string>
|
||||
<string name="main_drawer_group_contact_homepage">ホームページ</string>
|
||||
<string name="main_drawer_group_contact_help">ヘルプ</string>
|
||||
@@ -159,4 +160,5 @@
|
||||
<string name="unaccessible_download_folder">アンドロイド11以上では外部からのアプリ内部空間接近が不可能です。ダウンロードフォルダを変更しますか?</string>
|
||||
<string name="settings_networking">ネットワーク</string>
|
||||
<string name="settings_recover_downloads">ダウンロードデータベースを再構築</string>
|
||||
<string name="main_close_navigation_drawer">メニューを閉じる</string>
|
||||
</resources>
|
||||
@@ -36,6 +36,7 @@
|
||||
<string name="main_drawer_group_contact_github">Github</string>
|
||||
<string name="main_drawer_group_contact_help">도움말</string>
|
||||
<string name="main_drawer_group_contact_homepage">홈페이지</string>
|
||||
<string name="main_open_navigation_drawer">메뉴 열기</string>
|
||||
<string name="main_drawer_group_contact_title">문의</string>
|
||||
<string name="reader_fab_fullscreen">전체 화면</string>
|
||||
<string name="channel_download">다운로드</string>
|
||||
@@ -159,4 +160,5 @@
|
||||
<string name="unaccessible_download_folder">안드로이드 11 이상에서는 외부에서 현재 다운로드 폴더에 접근할 수 없습니다. 변경하시겠습니까?</string>
|
||||
<string name="settings_networking">네트워크</string>
|
||||
<string name="settings_recover_downloads">다운로드 데이터베이스 복구</string>
|
||||
<string name="main_close_navigation_drawer">메뉴 닫기</string>
|
||||
</resources>
|
||||
@@ -57,6 +57,8 @@
|
||||
<string name="main_destination_history">History</string>
|
||||
<string name="main_destination_downloads">Downloads</string>
|
||||
<string name="main_destination_favorites">Favorites</string>
|
||||
<string name="main_open_navigation_drawer">Open Navigation Drawer</string>
|
||||
<string name="main_close_navigation_drawer">Close Navigation Drawer</string>
|
||||
<string name="main_drawer_group_contact_title">Contact</string>
|
||||
<string name="main_drawer_group_contact_help">Help</string>
|
||||
<string name="main_drawer_group_contact_homepage">Visit homepage</string>
|
||||
|
||||
Reference in New Issue
Block a user