Add wide screen and landscape support

This commit is contained in:
Geoffroy Bonneville
2025-10-17 21:31:41 -04:00
parent 571b82dc98
commit 4e2f3c720c
4 changed files with 60 additions and 24 deletions

View File

@@ -15,7 +15,6 @@ import com.wismna.geoffroy.donext.data.local.dao.TaskListDao
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.ZonedDateTime
@Database( @Database(
entities = [TaskEntity::class, TaskListEntity::class], entities = [TaskEntity::class, TaskListEntity::class],

View File

@@ -5,17 +5,21 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import com.wismna.geoffroy.donext.presentation.screen.MainScreen import com.wismna.geoffroy.donext.presentation.screen.MainScreen
import com.wismna.geoffroy.donext.presentation.ui.theme.DoNextTheme import com.wismna.geoffroy.donext.presentation.ui.theme.DoNextTheme
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
DoNextTheme(darkTheme = isSystemInDarkTheme(), dynamicColor = false) { MainScreen() } val windowSizeClass = calculateWindowSizeClass(this)
DoNextTheme(darkTheme = isSystemInDarkTheme(), dynamicColor = false) { MainScreen(windowSizeClass) }
} }
} }
} }

View File

@@ -2,6 +2,7 @@
package com.wismna.geoffroy.donext.presentation.screen package com.wismna.geoffroy.donext.presentation.screen
import android.content.res.Configuration
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.slideOutHorizontally
@@ -24,6 +25,7 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalNavigationDrawer import androidx.compose.material3.ModalNavigationDrawer
import androidx.compose.material3.PermanentNavigationDrawer
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
@@ -34,6 +36,8 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberDrawerState import androidx.compose.material3.rememberDrawerState
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -44,6 +48,7 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
@@ -62,10 +67,10 @@ import kotlinx.coroutines.launch
@Composable @Composable
fun MainScreen( fun MainScreen(
windowSizeClass: WindowSizeClass,
viewModel: MainViewModel = hiltViewModel() viewModel: MainViewModel = hiltViewModel()
) { ) {
val navController = rememberNavController() val navController = rememberNavController()
val drawerState = rememberDrawerState(DrawerValue.Closed)
if (viewModel.isLoading) { if (viewModel.isLoading) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
@@ -84,13 +89,36 @@ fun MainScreen(
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
viewModel.setCurrentDestination(navBackStackEntry) viewModel.setCurrentDestination(navBackStackEntry)
ModalNavigationDrawer( val isExpandedScreen = windowSizeClass.widthSizeClass >= WindowWidthSizeClass.Medium
drawerContent = { val orientation = LocalConfiguration.current.orientation
MenuScreen (currentDestination = viewModel.currentDestination) val isLandscape = orientation == Configuration.ORIENTATION_LANDSCAPE
}, val showPermanentDrawer = isExpandedScreen || isLandscape
drawerState = drawerState
) { if (showPermanentDrawer) {
AppContent(viewModel = viewModel, navController = navController, drawerState = drawerState) PermanentNavigationDrawer(
drawerContent = {
MenuScreen(currentDestination = viewModel.currentDestination)
}
) {
AppContent(
viewModel = viewModel,
navController = navController
)
}
} else {
val drawerState = rememberDrawerState(DrawerValue.Closed)
ModalNavigationDrawer(
drawerContent = {
MenuScreen(currentDestination = viewModel.currentDestination)
},
drawerState = drawerState
) {
AppContent(
viewModel = viewModel,
navController = navController,
drawerState = drawerState
)
}
} }
} }
@@ -99,7 +127,7 @@ fun AppContent(
modifier : Modifier = Modifier, modifier : Modifier = Modifier,
viewModel: MainViewModel, viewModel: MainViewModel,
navController: NavHostController, navController: NavHostController,
drawerState: DrawerState drawerState: DrawerState? = null
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() } val snackbarHostState = remember { SnackbarHostState() }
@@ -108,7 +136,7 @@ fun AppContent(
viewModel.uiEventBus.events.collectLatest { event -> viewModel.uiEventBus.events.collectLatest { event ->
when (event) { when (event) {
is UiEvent.Navigate -> { is UiEvent.Navigate -> {
drawerState.close() drawerState?.close()
navController.navigate(event.route) navController.navigate(event.route)
} }
is UiEvent.NavigateBack -> navController.popBackStack() is UiEvent.NavigateBack -> navController.popBackStack()
@@ -140,17 +168,22 @@ fun AppContent(
actionIconContentColor = MaterialTheme.colorScheme.onPrimaryContainer actionIconContentColor = MaterialTheme.colorScheme.onPrimaryContainer
), ),
navigationIcon = { navigationIcon = {
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) { if (drawerState != null) {
if (viewModel.currentDestination.showBackButton) { CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) {
IconButton(onClick = { viewModel.navigateBack() }) { if (viewModel.currentDestination.showBackButton) {
Icon(Icons.AutoMirrored.Default.ArrowBack, contentDescription = "Back") IconButton(onClick = { viewModel.navigateBack() }) {
} Icon(
} else { Icons.AutoMirrored.Default.ArrowBack,
IconButton(onClick = { scope.launch { drawerState.open() } }) { contentDescription = "Back"
Icon( )
Icons.Default.Menu, }
contentDescription = "Open navigation drawer" } else {
) IconButton(onClick = { scope.launch { drawerState.open() } }) {
Icon(
Icons.Default.Menu,
contentDescription = "Open navigation drawer"
)
}
} }
} }
} }

View File

@@ -44,7 +44,7 @@ fun MenuScreen(
) { ) {
Column { Column {
Text( Text(
text = "Task Lists", text = "DoNext v2",
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
) )