Răsfoiți Sursa

design update

design update
Milan Jurkulak 2 ani în urmă
părinte
comite
4229f6e2a0

+ 4 - 2
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/MainSettingsPage.kt

@@ -22,7 +22,7 @@ import eu.mjdev.desktop.extensions.Modifier.rectShadow
 fun MainSettingsPage() = ControlCenterPage(
     icon = Icons.Filled.Home,
     name = "Home"
-)  {
+) {
     Box(
         modifier = Modifier.fillMaxSize()
     ) {
@@ -47,7 +47,9 @@ fun MainSettingsPage() = ControlCenterPage(
                 thickness = 2.dp
             )
             DateTime(
-                textColor = textColor,
+                modifier = Modifier.fillMaxWidth(),
+                timeTextColor = textColor,
+                dateTextColor = textColor,
                 backgroundColor = backgroundColor
             )
         }

+ 34 - 12
src/main/kotlin/eu/mjdev/desktop/components/custom/Clock.kt

@@ -1,11 +1,11 @@
 package eu.mjdev.desktop.components.custom
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.foundation.onClick
+import androidx.compose.runtime.*
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
@@ -14,12 +14,15 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.sp
 import eu.mjdev.desktop.components.text.TextWithShadow
+import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.extensions.Custom.ParsedList
 import eu.mjdev.desktop.extensions.Custom.dateFlow
 import eu.mjdev.desktop.extensions.Custom.timeFlow
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
+import kotlinx.coroutines.launch
 
 // todo remove params
+@OptIn(ExperimentalFoundationApi::class)
 @Composable
 fun Clock(
     modifier: Modifier = Modifier,
@@ -32,37 +35,56 @@ fun Clock(
     showTime: Boolean = true,
     showDate: Boolean = true,
     talkEveryHour: Boolean = true,
+    talkOnClick: Boolean = true
 ) = withDesktopScope {
+    val time = timeFlow.value
+    var lastTalk by rememberState("")
+    val talk: () -> Unit = {
+        scope.launch {
+            lastTalk = time
+            val parsed = ParsedList(time, ":")
+            ai.talk(
+                "It is ${parsed.firstOrNull()} hour, ${
+                    parsed.getOrNull(1)?.let { "$it minutes" }.orEmpty()
+                }, ${
+                    parsed.getOrNull(2)?.let { "$it seconds" }.orEmpty()
+                }"
+            )
+        }
+    }
     Box(
-        modifier = modifier,
+        modifier = modifier.onClick { if (talkOnClick) talk() },
         contentAlignment = Alignment.Center
     ) {
-        val time = timeFlow.value
-        Column {
+        Column(
+            horizontalAlignment = Alignment.CenterHorizontally
+        ) {
             if (showTime) TextWithShadow(
-                modifier = Modifier.fillMaxWidth(),
                 text = time,
                 textAlign = TextAlign.Center,
                 fontWeight = timeTextWeight,
                 fontSize = timeTextSize,
-                color = timeTextColor
+                color = timeTextColor,
+                maxLines = 1,
+                minLines = 1
             )
             if (showDate) TextWithShadow(
-                modifier = Modifier.fillMaxWidth(),
                 text = dateFlow.value,
                 textAlign = TextAlign.Center,
                 fontWeight = dateTextWeight,
                 fontSize = dateTextSize,
-                color = dateTextColor
+                color = dateTextColor,
+                maxLines = 1,
+                minLines = 1
             )
         }
         LaunchedEffect(time) {
-            if (time.isNotEmpty()) {
+            if (time.isNotEmpty() && lastTalk != time) {
                 val parsed = ParsedList(time, ":")
                 val isZeroSeconds = (parsed.getOrNull(2) ?: "-") == "00"
                 val isZeroMinutes = (parsed.getOrNull(1) ?: "-") == "00"
                 if (talkEveryHour && isZeroMinutes && isZeroSeconds) {
-                    ai.talk("It is ${parsed.firstOrNull()} hour")
+                    talk()
                 }
             }
         }

+ 30 - 9
src/main/kotlin/eu/mjdev/desktop/components/custom/DateTime.kt

@@ -3,27 +3,48 @@ package eu.mjdev.desktop.components.custom
 import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
 
 @Composable
 fun DateTime(
-    backgroundColor: Color=Color.Transparent,
-    textColor: Color = Color.Black
+    modifier: Modifier = Modifier,
+    backgroundColor: Color = Color.Transparent,
+    padding: Dp = 4.dp,
+    timeTextSize: TextUnit = 32.sp,
+    timeTextWeight: FontWeight = FontWeight.Bold,
+    timeTextColor: Color = Color.Black,
+    dateTextSize: TextUnit = 16.sp,
+    dateTextWeight: FontWeight = FontWeight.Bold,
+    dateTextColor: Color = Color.Black,
+    showTime: Boolean = true,
+    showDate: Boolean = true,
+    talkEveryHour: Boolean = false,
+    talkOnClick :Boolean = true
 ) = Box(
-    modifier = Modifier
-        .fillMaxWidth()
+    modifier = modifier
         .background(backgroundColor)
-        .padding(16.dp)
+        .padding(padding)
 ) {
     Clock(
-        modifier = Modifier.fillMaxWidth(),
-        timeTextColor = textColor,
-        dateTextColor = textColor
+        modifier = modifier,
+        timeTextSize = timeTextSize,
+        timeTextWeight = timeTextWeight,
+        timeTextColor = timeTextColor,
+        dateTextSize = dateTextSize,
+        dateTextWeight = dateTextWeight,
+        dateTextColor = dateTextColor,
+        showTime = showTime,
+        showDate = showDate,
+        talkEveryHour = talkEveryHour,
+        talkOnClick=talkOnClick
     )
 }
 

+ 52 - 71
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanel.kt

@@ -16,12 +16,10 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.onPlaced
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.unit.DpOffset
-import androidx.compose.ui.unit.DpSize
-import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.*
 import androidx.compose.ui.window.WindowPosition
 import eu.mjdev.desktop.components.desktoppanel.applets.DesktopMenuIcon
+import eu.mjdev.desktop.components.desktoppanel.applets.DesktopPanelDateTime
 import eu.mjdev.desktop.components.desktoppanel.applets.DesktopPanelFavoriteApps
 import eu.mjdev.desktop.components.desktoppanel.applets.DesktopPanelLanguage
 import eu.mjdev.desktop.components.sliding.SlidingMenu
@@ -33,6 +31,7 @@ import eu.mjdev.desktop.data.TooltipData
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
 import eu.mjdev.desktop.extensions.ColorUtils.lighter
 import eu.mjdev.desktop.extensions.Compose.height
+import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.extensions.Modifier.topShadow
 import eu.mjdev.desktop.helpers.animation.Animations.DesktopPanelEnterAnimation
 import eu.mjdev.desktop.helpers.animation.Animations.DesktopPanelExitAnimation
@@ -46,12 +45,10 @@ import eu.mjdev.desktop.windows.ChromeWindowState.Companion.rememberChromeWindow
 @Suppress("FunctionName")
 @Composable
 fun DesktopPanel(
-    dividerWidth: Dp = 4.dp,
     iconSize: DpSize = DpSize(56.dp, 56.dp),
     iconPadding: PaddingValues = PaddingValues(4.dp),
     iconOuterPadding: PaddingValues = PaddingValues(2.dp),
     showMenuIcon: Boolean = true,
-    panelContentPadding: PaddingValues = PaddingValues(4.dp),
     panelState: VisibilityState = rememberVisibilityState(),
     menuState: VisibilityState = rememberVisibilityState(),
     enterAnimation: EnterTransition = DesktopPanelEnterAnimation,
@@ -64,17 +61,19 @@ fun DesktopPanel(
         }
     },
     position: WindowPosition.Aligned = WindowPosition.Aligned(Alignment.BottomCenter),
-    onMenuIconClicked: () -> Unit = { },
-    onMenuIconContextMenuClicked: () -> Unit = { },
+    onMenuIconClicked: () -> Unit = {},
+    onMenuIconContextMenuClicked: () -> Unit = {},
     onFocusChange: (Boolean) -> Unit = {},
     onAppClick: DesktopScope.(App) -> Unit = { app -> startApp(app) },
-    onAppContextMenuClick: (App) -> Unit = { },
-    onLanguageClick: () -> Unit = { },
+    onAppContextMenuClick: (App) -> Unit = {},
+    onLanguageClick: () -> Unit = {},
+    onClockClick: () -> Unit = {}
 ) = withDesktopScope {
-    val tooltipState = remember { mutableStateOf<Any?>(null) }
+    val tooltipState = rememberState<Any?>(null)
+    val panelDividerWidth by rememberState(theme.panelDividerWidth)
     val panelHeight: (visible: Boolean) -> Dp = { visible ->
-        if (visible) iconSize.height + iconOuterPadding.height + tooltipHeight + panelContentPadding.height
-        else dividerWidth
+        if (visible) iconSize.height + iconOuterPadding.height + tooltipHeight + theme.panelContentPadding.times(2)
+        else panelDividerWidth
     }
     val size = remember(panelState.isVisible) {
         DpSize(containerSize.width, panelHeight(panelState.isVisible))
@@ -88,35 +87,25 @@ fun DesktopPanel(
         onFocusChange = { focused ->
             panelState.onFocusChange(focused)
             onFocusChange(focused)
-        }
-    ) {
-        SlidingMenu(
-            modifier = Modifier.fillMaxWidth(),
-            orientation = Vertical,
-            state = panelState,
-            onPointerEnter = {
-                panelState.show()
-                if (!menuState.isVisible) {
-                    windowState.requestFocus()
-                }
-            },
-            onPointerLeave = {
-                if (!menuState.isVisible) {
-                    panelState.hide()
-                }
+        }) {
+        SlidingMenu(modifier = Modifier.fillMaxWidth(), orientation = Vertical, state = panelState, onPointerEnter = {
+            panelState.show()
+            if (!menuState.isVisible) {
+                windowState.requestFocus()
             }
-        ) { isVisible ->
+        }, onPointerLeave = {
+            if (!menuState.isVisible) {
+                panelState.hide()
+            }
+        }) { isVisible ->
             Divider(
-                modifier = Modifier
-                    .fillMaxWidth()
-                    .height(dividerWidth),
+                modifier = Modifier.fillMaxWidth().height(panelDividerWidth),
                 color = Color.Transparent,
-                thickness = dividerWidth
+                thickness = panelDividerWidth
             )
             if (isVisible) {
                 TooltipArea(
-                    modifier = Modifier.fillMaxWidth().wrapContentHeight(),
-                    tooltip = {
+                    modifier = Modifier.fillMaxWidth().wrapContentHeight(), tooltip = {
                         Tooltip(
                             textColor = textColor,
                             borderColor = borderColor,
@@ -124,48 +113,33 @@ fun DesktopPanel(
                             converter = tooltipConverter,
                             backgroundColor = backgroundColor
                         )
-                    },
-                    tooltipPlacement = TooltipPlacement.CursorPoint(
-                        alignment = Alignment.TopEnd,
-                        offset = DpOffset(32.dp, 32.dp)
+                    }, tooltipPlacement = TooltipPlacement.CursorPoint(
+                        alignment = Alignment.TopEnd, offset = DpOffset(32.dp, 32.dp)
                     )
                 ) {
                     Column {
                         Box(
-                            modifier = Modifier
-                                .fillMaxWidth()
-                                .height(tooltipHeight)
+                            modifier = Modifier.fillMaxWidth().height(tooltipHeight)
                         )
                         Column(
-                            modifier = Modifier
-                                .fillMaxWidth()
-                                .wrapContentHeight()
-                                .background(
-                                    brush = Brush.verticalGradient(
-                                        colors = listOf(
-                                            backgroundColor.alpha(0.3f),
-                                            backgroundColor.alpha(0.7f),
-                                            backgroundColor.alpha(0.8f),
-                                        )
+                            modifier = Modifier.fillMaxWidth().wrapContentHeight().background(
+                                brush = Brush.verticalGradient(
+                                    colors = listOf(
+                                        backgroundColor.alpha(0.3f),
+                                        backgroundColor.alpha(0.7f),
+                                        backgroundColor.alpha(0.8f),
                                     )
                                 )
-                                .topShadow(
-                                    color = borderColor.alpha(0.3f),
-                                    blur = 4.dp
-                                )
-                                .onPlaced(panelState::onPlaced),
+                            ).topShadow(
+                                color = borderColor.alpha(0.3f), blur = 4.dp
+                            ).onPlaced(panelState::onPlaced),
                         ) {
                             Divider(
-                                modifier = Modifier
-                                    .fillMaxWidth()
-                                    .height(2.dp),
-                                color = borderColor,
-                                thickness = 2.dp
+                                modifier = Modifier.fillMaxWidth().height(2.dp), color = borderColor, thickness = 2.dp
                             )
                             Box(
-                                modifier = Modifier.fillMaxWidth()
-                                    .padding(top = 4.dp)
-                                    .padding(panelContentPadding)
+                                modifier = Modifier.fillMaxWidth().padding(top = 4.dp)
+                                    .padding(theme.panelContentPadding)
                             ) {
                                 if (showMenuIcon) {
                                     DesktopMenuIcon(
@@ -192,11 +166,18 @@ fun DesktopPanel(
                                     onAppClick = { app -> onAppClick(app) },
                                     onContextMenuClick = onAppContextMenuClick
                                 )
-                                DesktopPanelLanguage(
-                                    modifier = Modifier.align(Alignment.CenterEnd),
-                                    onTooltip = { item -> tooltipState.value = item },
-                                    onClick = onLanguageClick
-                                )
+                                DesktopPanelTray(
+                                    modifier = Modifier.align(Alignment.CenterEnd).padding(end = 16.dp),
+                                ) {
+                                    DesktopPanelLanguage(
+                                        onTooltip = { item -> tooltipState.value = item },
+                                        onClick = onLanguageClick
+                                    )
+                                    DesktopPanelDateTime(
+                                        onTooltip = { item -> tooltipState.value = item },
+                                        onClick = onClockClick
+                                    )
+                                }
                             }
                         }
                     }

+ 3 - 3
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelText.kt

@@ -26,17 +26,17 @@ fun DesktopPanelText(
     modifier: Modifier = Modifier,
     text: String = "text",
     textColor: Color = Color.White,
-    backgroundHover: Color = Color.Red,
+    backgroundHover: Color = Color.White.copy(alpha = 0.4f),
     textPadding: PaddingValues = PaddingValues(4.dp),
     buttonState: MutableState<Boolean> = rememberState(false),
-    onToolTip: (item: Any?) -> Unit = {},
+    onTooltip: (item: Any?) -> Unit = {},
     onClick: () -> Unit = {},
 ) = Box(
     modifier = modifier
         .wrapContentSize()
         .onMouseEnter {
             buttonState.value = true
-            onToolTip(text)
+            onTooltip(text)
         }
         .onMouseLeave {
             buttonState.value = false

+ 29 - 0
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelTray.kt

@@ -0,0 +1,29 @@
+package eu.mjdev.desktop.components.desktoppanel
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
+
+// todo
+@Composable
+fun DesktopPanelTray(
+    modifier: Modifier = Modifier,
+    round: Dp = 8.dp,
+    padding: PaddingValues = PaddingValues(
+        horizontal = 4.dp
+    ),
+    content: @Composable RowScope.() -> Unit = {}
+) = withDesktopScope {
+    Row(
+        modifier = modifier.background(backgroundColor, RoundedCornerShape(round)).padding(padding),
+        content = content
+    )
+}

+ 69 - 0
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopPanelDateTime.kt

@@ -0,0 +1,69 @@
+package eu.mjdev.desktop.components.desktoppanel.applets
+
+import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.material.Button
+import androidx.compose.material.ButtonDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import eu.mjdev.desktop.components.custom.DateTime
+import eu.mjdev.desktop.extensions.Compose.color
+import eu.mjdev.desktop.extensions.Compose.noElevation
+import eu.mjdev.desktop.extensions.Compose.onMouseEnter
+import eu.mjdev.desktop.extensions.Compose.onMouseLeave
+import eu.mjdev.desktop.extensions.Compose.rememberState
+import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
+
+@Composable
+fun DesktopPanelDateTime(
+    modifier: Modifier = Modifier,
+    buttonState: MutableState<Boolean> = rememberState(false),
+    padding: Dp = 4.dp,
+    backgroundHover: Color = Color.White.copy(alpha = 0.4f),
+    timeTextSize: TextUnit = 14.sp,
+    dateTextSize: TextUnit = 10.sp,
+    onTooltip: (item: Any?) -> Unit = {},
+    onClick: () -> Unit = {},
+) = withDesktopScope {
+    Box(
+        modifier = modifier
+            .wrapContentSize()
+            .onMouseEnter {
+                buttonState.value = true
+                onTooltip(null) // todo
+            }
+            .onMouseLeave {
+                buttonState.value = false
+            }
+    ) {
+        Button(
+            modifier = Modifier.padding(padding),
+            contentPadding = PaddingValues(horizontal = 4.dp),
+            onClick = onClick,
+            colors = ButtonDefaults.color(if (buttonState.value) backgroundHover else Color.Transparent),
+            elevation = ButtonDefaults.noElevation()
+        ) {
+            DateTime(
+                backgroundColor = Color.Transparent,
+                padding = 1.dp,
+                dateTextSize = dateTextSize,
+                timeTextSize = timeTextSize,
+                timeTextColor = iconsTintColor,
+                dateTextColor = iconsTintColor,
+            )
+        }
+    }
+}
+
+@Preview
+@Composable
+fun DesktopPanelDateTimePreview() = DesktopPanelDateTime()

+ 3 - 4
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopPanelLanguage.kt

@@ -3,7 +3,6 @@ package eu.mjdev.desktop.components.desktoppanel.applets
 import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
 import eu.mjdev.desktop.components.desktoppanel.DesktopPanelText
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
@@ -18,9 +17,9 @@ fun DesktopPanelLanguage(
     DesktopPanelText(
         modifier = modifier,
         text = api.appsProvider.currentLocale.country,
-        backgroundHover = Color.White.copy(alpha = 0.4f),
-        onToolTip = onTooltip,
-        onClick = onClick
+        onTooltip = onTooltip,
+        onClick = onClick,
+        textColor = iconsTintColor
     )
 }
 

+ 7 - 12
src/main/kotlin/eu/mjdev/desktop/components/file/FolderIcon.kt

@@ -1,13 +1,7 @@
 package eu.mjdev.desktop.components.file
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
-import androidx.compose.foundation.layout.wrapContentSize
+import androidx.compose.foundation.layout.*
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
@@ -19,11 +13,11 @@ import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.draggable.DraggableView
 import eu.mjdev.desktop.components.fonticon.FontIcon
 import eu.mjdev.desktop.components.text.TextWithShadow
-import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
-import java.io.File
-import eu.mjdev.desktop.extensions.Custom.plus
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Custom.plus
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
+import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
+import java.io.File
 
 @Suppress("FunctionName")
 @Composable
@@ -32,11 +26,12 @@ fun FolderIcon(
     customName: String? = null,
     dragEnabled: Boolean = true,
     iconSize: DpSize = DpSize(128.dp, 128.dp),
+    modifier: Modifier = Modifier,
     zIndex: () -> Int = { 0 },
     onDragStart: () -> Unit = {},
     onDragEnd: () -> Unit = {},
-    onClick: () -> Unit = {},
     onContextMenuClick: () -> Unit = {},
+    onClick: () -> Unit = {},
 ) = withDesktopScope {
     val iconName = remember(path) {
         path.let {
@@ -51,7 +46,7 @@ fun FolderIcon(
     val iconId: Int = remember(path) { iconSet.iconForName(iconName) ?: "?".toInt() }
     val computedSize = remember(path) { iconSize + 2.dp }
     DraggableView(
-        modifier = Modifier.wrapContentSize(),
+        modifier = modifier,
         dragEnabled = dragEnabled,
         zIndex = zIndex().toFloat(),
         onClick = onClick,

+ 62 - 53
src/main/kotlin/eu/mjdev/desktop/components/file/FolderView.kt

@@ -1,23 +1,26 @@
 package eu.mjdev.desktop.components.file
 
-import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.*
-import androidx.compose.foundation.gestures.Orientation
-import androidx.compose.foundation.layout.*
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.MutableState
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
 //import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
 //import androidx.compose.ui.graphics.Color
 //import androidx.compose.ui.unit.dp
 //import com.composables.core.*
-import eu.mjdev.desktop.data.DesktopFolderItem
 //import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
+import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.ScrollState
+import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.foundation.horizontalScroll
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.runtime.*
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.data.DesktopFolderItem
 import eu.mjdev.desktop.extensions.Modifier.conditional
 import eu.mjdev.desktop.provider.DesktopProvider
 import eu.mjdev.desktop.provider.DesktopProvider.Companion.LocalDesktop
+import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import java.io.File
 
 // ScreencastHelper
@@ -38,57 +41,45 @@ fun FolderView(
     showHidden: Boolean = false,
     directoryFirst: Boolean = true,
     showHomeFolder: Boolean = false,
+    iconSpacing: Dp = 2.dp,
     path: File? = File("/"),
     api: DesktopProvider = LocalDesktop.current,
-    files: List<DesktopFolderItem> = remember(path) {
-        path?.list()
-            ?.toList<String>()
-            ?.sorted()
-            ?.filter { s ->
-                (showHidden == true) || (!s.startsWith("."))
-            }?.map { filePath ->
-                File(filePath)
-            }?.sortedByDescending {
-                (directoryFirst == false) || (it.extension.isEmpty()) // todo isDirectory
-            }?.map { path ->
-                DesktopFolderItem(path)
-            }?.toMutableList()
-            ?.apply {
-                if (showHomeFolder) add(
-                    DesktopFolderItem(
-                        path = api.homeDir,
-                        customName = "Home",
-                        priority = 1
-                    )
-                )
-            }?.sortedByDescending {
-                it.priority
-            } ?: emptyList()
-    },
-    zIndexState: MutableState<Int> = remember { mutableStateOf(files.size) },
+    zIndexState: MutableState<Int> = remember { mutableStateOf(0) },
     orientation: Orientation = Orientation.Vertical,
     scrollState: ScrollState = rememberScrollState(),
 //    scrollbarsState: ScrollAreaState = rememberScrollAreaState(scrollState)
-) = Box(
-    modifier = modifier.conditional(
-        condition = orientation == Orientation.Horizontal,
-        onTrue = {
-            verticalScroll(
-                state = scrollState,
-                enabled = scrollState.canScrollForward
-            )
-        },
-        onFalse = {
-            horizontalScroll(
-                state = scrollState,
-                enabled = scrollState.canScrollForward
-            )
+) = withDesktopScope {
+    val files by remember(path) {
+        derivedStateOf {
+            path?.list()
+                ?.toList<String>()
+                ?.sorted()
+                ?.filter { s ->
+                    (showHidden == true) || (!s.startsWith("."))
+                }?.map { filePath ->
+                    File(filePath)
+                }?.sortedByDescending {
+                    (directoryFirst == false) || (it.extension.isEmpty()) // todo isDirectory
+                }?.map { path ->
+                    DesktopFolderItem(path)
+                }?.toMutableList()
+                ?.apply {
+                    if (showHomeFolder) add(
+                        DesktopFolderItem(
+                            path = api.homeDir,
+                            customName = "Home",
+                            priority = 1
+                        )
+                    )
+                }?.sortedByDescending {
+                    it.priority
+                } ?: emptyList()
         }
-    )
-) {
+    }
     val content: @Composable () -> Unit = {
         files.forEach { file ->
             FolderIcon(
+                modifier = Modifier.padding(iconSpacing),
                 path = file.path,
                 customName = file.customName,
                 zIndex = { zIndexState.value },
@@ -98,6 +89,23 @@ fun FolderView(
             )
         }
     }
+    Box(
+        modifier = modifier.conditional(
+            condition = orientation == Orientation.Horizontal,
+            onTrue = {
+                verticalScroll(
+                    state = scrollState,
+                    enabled = scrollState.canScrollForward
+                )
+            },
+            onFalse = {
+                horizontalScroll(
+                    state = scrollState,
+                    enabled = scrollState.canScrollForward
+                )
+            }
+        )
+    ) {
 //    ScrollArea(
 //        state = scrollbarsState
 //    ) {
@@ -136,9 +144,10 @@ fun FolderView(
 //                )
 //            }
 //        }
+        }
     }
 }
 
 @Preview
 @Composable
-fun FolderViewPreview() = FolderView()
+fun FolderViewPreview() = FolderView()

+ 37 - 16
src/main/kotlin/eu/mjdev/desktop/components/info/InfoWindow.kt

@@ -3,52 +3,73 @@ package eu.mjdev.desktop.components.info
 import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.background
 import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.*
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontStyle
+import androidx.compose.ui.text.font.FontWeight
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
 import androidx.compose.ui.window.WindowPosition
 import eu.mjdev.desktop.components.background.BackgroundImage
-import eu.mjdev.desktop.extensions.Compose.rememberState
+import eu.mjdev.desktop.components.button.ButtonPrimary
+import eu.mjdev.desktop.components.sliding.base.VisibilityState
+import eu.mjdev.desktop.components.sliding.base.VisibilityState.Companion.rememberVisibilityState
+import eu.mjdev.desktop.components.text.TextAny
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import eu.mjdev.desktop.windows.ChromeWindow
 
 @Suppress("FunctionName")
 @Composable
-fun InfoWindow() = withDesktopScope {
-    var visible by rememberState(true)
+fun InfoWindow(
+    state: VisibilityState = rememberVisibilityState(),
+    showInstallWindow: () -> Unit = {}
+) = withDesktopScope {
     ChromeWindow(
-        visible = visible,
+        visible = state.isVisible,
         size = DpSize(808.dp, 608.dp),
         position = WindowPosition.Aligned(Alignment.Center)
     ) {
         Box(
             modifier = Modifier.fillMaxSize().clickable {
-                visible = false
+                state.hide()
             }
         ) {
             Box(
                 modifier = Modifier.fillMaxSize()
                     .background(backgroundColor),
-                contentAlignment = Alignment.Center
+                contentAlignment = Alignment.BottomStart
             ) {
                 BackgroundImage(
                     modifier = Modifier.fillMaxSize()
                 )
+                TextAny(
+                    modifier = Modifier.padding(bottom = 128.dp, start = 16.dp),
+                    text = "Welcome to mjdev desktop",
+                    fontStyle = FontStyle.Italic,
+                    fontWeight = FontWeight.Bold,
+                    fontSize = 48.sp
+                )
                 Box(
                     modifier = Modifier.fillMaxWidth()
-                        .height(200.dp)
+                        .height(128.dp)
                         .background(iconsTintColor)
-                        .align(Alignment.BottomCenter)
+                        .align(Alignment.BottomCenter),
                 ) {
-                    // todo
+                    Row(
+                        modifier = Modifier.fillMaxWidth()
+                            .padding(16.dp)
+                            .align(Alignment.BottomEnd),
+                        horizontalArrangement = Arrangement.End
+                    ) {
+                        ButtonPrimary(
+                            text = "install mjdev desktop",
+                            visible = !api.isInstalled,
+                            onClick = showInstallWindow,
+                        )
+                    }
                 }
             }
         }
@@ -57,4 +78,4 @@ fun InfoWindow() = withDesktopScope {
 
 @Preview
 @Composable
-fun InfoWindowPreview() = InfoWindow()
+fun InfoWindowPreview() = InfoWindow()

+ 60 - 0
src/main/kotlin/eu/mjdev/desktop/components/installer/InfoWindow.kt

@@ -0,0 +1,60 @@
+package eu.mjdev.desktop.components.installer
+
+import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.window.WindowPosition
+import eu.mjdev.desktop.components.background.BackgroundImage
+import eu.mjdev.desktop.components.sliding.base.VisibilityState
+import eu.mjdev.desktop.components.sliding.base.VisibilityState.Companion.rememberVisibilityState
+import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
+import eu.mjdev.desktop.windows.ChromeWindow
+
+@Suppress("FunctionName")
+@Composable
+fun Installer(
+    state: VisibilityState = rememberVisibilityState()
+) = withDesktopScope {
+    ChromeWindow(
+        visible = state.isVisible,
+        size = DpSize(808.dp, 608.dp),
+        position = WindowPosition.Aligned(Alignment.Center)
+    ) {
+        Box(
+            modifier = Modifier.fillMaxSize().clickable {
+                state.hide()
+            }
+        ) {
+            Box(
+                modifier = Modifier.fillMaxSize()
+                    .background(backgroundColor),
+                contentAlignment = Alignment.Center
+            ) {
+                BackgroundImage(
+                    modifier = Modifier.fillMaxSize()
+                )
+                Box(
+                    modifier = Modifier.fillMaxWidth()
+                        .height(200.dp)
+                        .background(iconsTintColor)
+                        .align(Alignment.BottomCenter)
+                ) {
+                    // todo
+                }
+            }
+        }
+    }
+}
+
+@Preview
+@Composable
+fun InfoWindowPreview() = Installer()

+ 14 - 1
src/main/kotlin/eu/mjdev/desktop/components/main/MainWindow.kt

@@ -10,6 +10,8 @@ import eu.mjdev.desktop.components.controlcenter.ControlCenter
 import eu.mjdev.desktop.components.desktop.Desktop
 import eu.mjdev.desktop.components.desktoppanel.DesktopPanel
 import eu.mjdev.desktop.components.greeter.Greeter
+import eu.mjdev.desktop.components.info.InfoWindow
+import eu.mjdev.desktop.components.installer.Installer
 import eu.mjdev.desktop.components.sliding.base.VisibilityState.Companion.rememberVisibilityState
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import eu.mjdev.desktop.windows.DesktopWindow
@@ -19,6 +21,8 @@ fun MainWindow() = withDesktopScope {
     val controlCenterState = rememberVisibilityState()
     val panelState = rememberVisibilityState()
     val menuState = rememberVisibilityState()
+    val installWindowSate = rememberVisibilityState()
+    val infoWindowSate = rememberVisibilityState(false) //(api.isFirstStart || api.isDebug) // todo
     val handleMenuFocus: (Boolean) -> Unit = { focus ->
         if (!menuState.isWindowFocus && !focus && !controlCenterState.isWindowFocus) {
             menuState.hide()
@@ -60,7 +64,16 @@ fun MainWindow() = withDesktopScope {
             onFocusChange = { focus -> handleControlCenterFocus(focus) }
         )
         Greeter()
-//        InfoWindow()
+        InfoWindow(
+            state = infoWindowSate,
+            showInstallWindow = {
+                infoWindowSate.hide()
+                installWindowSate.show()
+            }
+        )
+        Installer(
+            state = installWindowSate
+        )
     }
     DisposableEffect(Unit) {
         onDispose {

+ 9 - 1
src/main/kotlin/eu/mjdev/desktop/data/Theme.kt

@@ -16,6 +16,8 @@ class Theme(
     backgroundRotationDelay: Long,
 
     panelLocation: PanelLocation,
+    panelDividerWidth: Dp,
+    panelContentPadding: Dp,
     panelHideDelay: Long,
 
     controlCenterLocation: ControlCenterLocation,
@@ -39,6 +41,8 @@ class Theme(
 
     val panelLocationState = mutableStateOf(panelLocation)
     val panelHideDelayState = mutableStateOf(panelHideDelay)
+    val panelDividerWidthState = mutableStateOf(panelDividerWidth)
+    val panelContentPaddingState = mutableStateOf(panelContentPadding)
 
     val controlCenterLocationState = mutableStateOf(controlCenterLocation)
     val controlPanelHideDelayState = mutableStateOf(controlPanelHideDelay)
@@ -61,6 +65,8 @@ class Theme(
         }
 
     val panelLocation get() = panelLocationState.value
+    val panelDividerWidth get() = panelDividerWidthState.value
+    val panelContentPadding get() = panelContentPaddingState.value
     val panelHideDelay get() = panelHideDelayState.value
 
     val controlCenterBackgroundAlphaState = mutableStateOf(controlCenterBackgroundAlpha)
@@ -93,13 +99,15 @@ class Theme(
                 backgroundColor = Color.SuperDarkGray,
 
                 panelLocation = PanelLocation.Bottom,
+                panelDividerWidth = 8.dp,
+                panelContentPadding = 4.dp,
                 panelHideDelay = 5000L,
 
                 controlCenterLocation = ControlCenterLocation.Right,
                 controlPanelHideDelay = 5000L,
                 controlCenterExpandedWidth = 480.dp,
                 controlCenterDividerColor = Color.SuperDarkGray,
-                controlCenterDividerWidth = 2.dp,
+                controlCenterDividerWidth = 8.dp,
                 controlCenterIconColor = Color.White,
                 controlCenterIconSize = DpSize(32.dp, 32.dp),
                 controlCenterBackgroundAlpha = 0.8f,