diff --git a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/Platform.android.kt b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/Platform.android.kt index 58cfce5..2074d5b 100644 --- a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/Platform.android.kt +++ b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/Platform.android.kt @@ -1,12 +1,29 @@ package net.codinux.banking.ui import android.os.Build +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.unit.dp import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers actual val Dispatchers.IOorDefault: CoroutineDispatcher get() = Dispatchers.IO +@Composable +actual fun rememberScreenSizeInfo(): ScreenSizeInfo { + val config = LocalConfiguration.current + + return remember(config) { + ScreenSizeInfo( + heightDp = config.screenHeightDp.dp, + widthDp = config.screenWidthDp.dp + ) + } +} + + class AndroidPlatform : Platform { override val name: String = "Android ${Build.VERSION.SDK_INT}" diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt index 17645f8..c1a4d2b 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt @@ -35,8 +35,15 @@ fun App() { // the same values as in BottomBar, but LocalContentColor.current and LocalContentAlpha.current have a different value there val snackbarTextColor = MaterialTheme.colors.onPrimary.copy(alpha = 0.74f) // 0.74f = ContentAlpha.HighContrastContentAlpha.medium + val screenSizeInfo = rememberScreenSizeInfo() + + val isMobile = derivedStateOf { screenSizeInfo.getUiType() == UiType.COMPACT }.value + // we want to place the FAB half size into the BottomBar so we have to add some top padding to it - val fabPositionAdjustment = 44.dp // FabSpacing = 16.dp + FAB height (= 56.dp) / 2 + val fabPositionAdjustment = if (isMobile) 44.dp // FabSpacing = 16.dp + FAB height (= 56.dp) / 2 + else (-10).dp + + val desktopDrawerWidth = 350.dp val uiState = DI.uiState @@ -46,17 +53,15 @@ fun App() { val snackbarHostState = remember { SnackbarHostState() } - val coroutineScope = rememberCoroutineScope() + var isInitialized by remember { mutableStateOf(false) } - coroutineScope.launch { - DI.init() - } + val coroutineScope = rememberCoroutineScope() MaterialTheme(colors = colors, typography = typography) { Scaffold( scaffoldState = rememberScaffoldState(drawerState, snackbarHostState), - bottomBar = { BottomBar() }, + bottomBar = { if (isMobile) BottomBar() else null }, backgroundColor = Colors.Zinc100, floatingActionButton = { FloatingActionButton( @@ -67,14 +72,15 @@ fun App() { Icon(Icons.Filled.Add, contentDescription = "Add a bank account") } }, - drawerContent = { SideMenuContent() }, + drawerContent = { if (isMobile) SideMenuContent() else null }, drawerBackgroundColor = Colors.DrawerContentBackground, snackbarHost = { snackbarHostState -> SnackbarHost( hostState = snackbarHostState ) { data -> Snackbar( - modifier = Modifier.offset(y = fabPositionAdjustment - 4.dp).padding(horizontal = 12.dp), + modifier = Modifier.offset(y = fabPositionAdjustment - 4.dp) + .let { if (isMobile) it.padding(horizontal = 12.dp) else it.padding(start = desktopDrawerWidth + 6.dp, end = 2.dp) }, action = { if (data.actionLabel == null) null else { TextButton( onClick = { data.performAction() }, @@ -88,7 +94,36 @@ fun App() { } } ) { scaffoldPadding -> - AppContent(scaffoldPadding, uiState, uiSettings, snackbarHostState) + if (isMobile) { + AppContent(scaffoldPadding, uiState, uiSettings, snackbarHostState, isMobile) + } else { + Row(Modifier.fillMaxSize()) { + Column(Modifier.width(desktopDrawerWidth)) { + SideMenuContent() + } + + Column(Modifier.fillMaxSize().weight(1f).padding(start = 6.dp)) { + Row(Modifier.fillMaxWidth().weight(1f)) { + AppContent(scaffoldPadding, uiState, uiSettings, snackbarHostState, isMobile) + } + + Row(Modifier.fillMaxWidth()) { + BottomBar(false) + } + } + } + } + } + } + + + LaunchedEffect(isInitialized) { + if (isInitialized == false) { + isInitialized = true + + coroutineScope.launch { + DI.init() + } } } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/Platform.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/Platform.kt index f79dc1a..be0eb47 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/Platform.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/Platform.kt @@ -1,11 +1,37 @@ package net.codinux.banking.ui +import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers expect val Dispatchers.IOorDefault: CoroutineDispatcher +@Composable +expect fun rememberScreenSizeInfo(): ScreenSizeInfo + +data class ScreenSizeInfo( + val heightDp: Dp, + val widthDp: Dp +) + +fun ScreenSizeInfo.getUiType(): UiType { + return when (widthDp){ + in 0.dp..600.dp -> UiType.COMPACT + in 600.dp..840.dp -> UiType.MEDIUM + else -> UiType.EXPANDED + } +} + +enum class UiType { + COMPACT, + MEDIUM, + EXPANDED +} + + expect fun getPlatform(): Platform interface Platform { diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/AppContent.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/AppContent.kt index ed946ce..9f58948 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/AppContent.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/AppContent.kt @@ -15,11 +15,12 @@ fun AppContent( scaffoldPadding: PaddingValues, uiState: UiState, uiSettings: UiSettings, - snackbarHostState: SnackbarHostState + snackbarHostState: SnackbarHostState, + isMobile: Boolean ) { Column(Modifier.fillMaxSize().padding(scaffoldPadding), horizontalAlignment = Alignment.CenterHorizontally) { - TransactionsList(uiState, uiSettings) + TransactionsList(uiState, uiSettings, isMobile) StateHandler(uiState, snackbarHostState) } diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/BottomBar.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/BottomBar.kt index 6b1b49a..0c209f6 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/BottomBar.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/BottomBar.kt @@ -38,7 +38,7 @@ private val uiState = DI.uiState private val IconWidth = 48.dp @Composable -fun BottomBar() { +fun BottomBar(showMenuDrawer: Boolean = true) { val userAccounts by uiState.userAccounts.collectAsState() val transactionsFilter by uiState.transactionsFilter.collectAsState() @@ -50,20 +50,17 @@ fun BottomBar() { val coroutineScope = rememberCoroutineScope() - val configuration = LocalViewConfiguration.current - println("config: $configuration") - - val windowInfo = LocalWindowInfo.current - println("windowInfo: $windowInfo") - - - BottomAppBar(modifier = Modifier.background(Colors.Accent)) { - IconButton( - onClick = { coroutineScope.launch { - uiState.drawerState.value.toggle() - } } - ) { - Icon(Icons.Filled.Menu, contentDescription = "Open Navigation Drawer with sidebar menu") + BottomAppBar { + if (showMenuDrawer) { + IconButton( + onClick = { coroutineScope.launch { + uiState.drawerState.value.toggle() + } } + ) { + Icon(Icons.Filled.Menu, contentDescription = "Open Navigation Drawer with sidebar menu") + } + } else { + Spacer(Modifier.width(6.dp)) // or show app icon? } Row(Modifier.fillMaxWidth().padding(end = 64.dp)) { // 72.dp = leave space for Floating Action Button diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/SideMenuContent.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/SideMenuContent.kt index 6987917..572d3de 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/SideMenuContent.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/appskeleton/SideMenuContent.kt @@ -57,7 +57,7 @@ fun SideMenuContent() { val coroutineScope = rememberCoroutineScope() - Column(Modifier.verticalScroll(ScrollState(0), enabled = true)) { + Column(Modifier.background(Colors.DrawerContentBackground).verticalScroll(ScrollState(0), enabled = true)) { Column(Modifier.fillMaxWidth().height(HeaderHeight.dp).background(HeaderBackground).padding(16.dp)) { Spacer(Modifier.weight(1f)) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/transactions/TransactionsList.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/transactions/TransactionsList.kt index d0ad8a9..665f26e 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/transactions/TransactionsList.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/transactions/TransactionsList.kt @@ -23,7 +23,7 @@ private val calculator = DI.calculator private val formatUtil = DI.formatUtil @Composable -fun TransactionsList(uiState: UiState, uiSettings: UiSettings) { +fun TransactionsList(uiState: UiState, uiSettings: UiSettings, isMobile: Boolean = true) { val userAccounts by uiState.userAccounts.collectAsState() val userAccountsId by remember(userAccounts) { derivedStateOf { userAccounts.associateBy { it.id } } @@ -46,7 +46,7 @@ fun TransactionsList(uiState: UiState, uiSettings: UiSettings) { val transactionsListModifier = Modifier.fillMaxSize() - Column(Modifier.fillMaxSize().padding(horizontal = 8.dp)) { + Column(Modifier.fillMaxSize().let { if (isMobile) it.padding(horizontal = 8.dp) else it.padding(end = 2.dp) }) { Row(Modifier.fillMaxWidth().height(32.dp).background(Colors.Zinc200), verticalAlignment = Alignment.CenterVertically) { Text("${transactionsToDisplay.size} Umsätze") Spacer(Modifier.weight(1f)) diff --git a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.desktop.kt b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.desktop.kt index 8297a7c..af796a7 100644 --- a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.desktop.kt +++ b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/Platform.desktop.kt @@ -1,11 +1,30 @@ package net.codinux.banking.ui +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalWindowInfo import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers actual val Dispatchers.IOorDefault: CoroutineDispatcher get() = Dispatchers.IO +@OptIn(ExperimentalComposeUiApi::class) +@Composable +actual fun rememberScreenSizeInfo(): ScreenSizeInfo { + val density = LocalDensity.current + val config = LocalWindowInfo.current.containerSize + + return remember(density, config) { + ScreenSizeInfo( + heightDp = with(density) { config.height.toDp() }, + widthDp = with(density) { config.width.toDp() } + ) + } +} + class JVMPlatform: Platform { override val name: String = "Java ${System.getProperty("java.version")}" diff --git a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/main.kt b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/main.kt index 04026bb..80009e6 100644 --- a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/main.kt +++ b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/main.kt @@ -24,7 +24,7 @@ fun main() = application { onCloseRequest = ::exitApplication, title = "Bankmeister", icon = painterResource(Res.drawable.AppIcon_svg), - state = WindowState(position = WindowPosition(Alignment.Center), size = DpSize(900.dp, 800.dp)), + state = WindowState(position = WindowPosition(Alignment.Center), size = DpSize(1000.dp, 800.dp)), ) { File("data/db").mkdirs() DI.setRepository(JdbcSqliteDriver("jdbc:sqlite:data/db/Bankmeister.db").apply { diff --git a/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/Platform.js.kt b/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/Platform.js.kt index 9696004..12fdfff 100644 --- a/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/Platform.js.kt +++ b/composeApp/src/jsMain/kotlin/net/codinux/banking/ui/Platform.js.kt @@ -1,11 +1,30 @@ package net.codinux.banking.ui +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalWindowInfo import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers actual val Dispatchers.IOorDefault: CoroutineDispatcher get() = Dispatchers.Default +@OptIn(ExperimentalComposeUiApi::class) +@Composable +actual fun rememberScreenSizeInfo(): ScreenSizeInfo { + val density = LocalDensity.current + val config = LocalWindowInfo.current.containerSize + + return remember(density, config) { + ScreenSizeInfo( + heightDp = with(density) { config.height.toDp() }, + widthDp = with(density) { config.width.toDp() } + ) + } +} + class JsPlatform: Platform { override val name: String = "Web with Kotlin/Js"