Ver código fonte

code improvements - previews 2/2

milan jurkulák 1 ano atrás
pai
commit
48dc9b1a97
95 arquivos alterados com 1309 adições e 452 exclusões
  1. 1 1
      README.md
  2. 1 1
      build.gradle.kts
  3. 145 30
      src/main/kotlin/eu/mjdev/desktop/components/appbar/AppBar.kt
  4. 18 4
      src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsBottomBar.kt
  5. 4 7
      src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsList.kt
  6. 8 3
      src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenu.kt
  7. 12 2
      src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenuActions.kt
  8. 13 9
      src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenuApp.kt
  9. 13 9
      src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenuCategory.kt
  10. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/background/BackgroundImage.kt
  11. 8 4
      src/main/kotlin/eu/mjdev/desktop/components/blur/BlurPanel.kt
  12. 2 9
      src/main/kotlin/eu/mjdev/desktop/components/button/ButtonPrimary.kt
  13. 2 9
      src/main/kotlin/eu/mjdev/desktop/components/button/ButtonSecondary.kt
  14. 2 7
      src/main/kotlin/eu/mjdev/desktop/components/button/TransparentButton.kt
  15. 16 1
      src/main/kotlin/eu/mjdev/desktop/components/card/Card.kt
  16. 48 5
      src/main/kotlin/eu/mjdev/desktop/components/card/ClassicCard.kt
  17. 78 28
      src/main/kotlin/eu/mjdev/desktop/components/card/CompactCard.kt
  18. 33 17
      src/main/kotlin/eu/mjdev/desktop/components/card/FocusableCard.kt
  19. 21 1
      src/main/kotlin/eu/mjdev/desktop/components/card/ItemCard.kt
  20. 36 27
      src/main/kotlin/eu/mjdev/desktop/components/card/PhotoCard.kt
  21. 46 16
      src/main/kotlin/eu/mjdev/desktop/components/card/WideClassicCard.kt
  22. 26 7
      src/main/kotlin/eu/mjdev/desktop/components/card/base/CardDefaults.kt
  23. 18 8
      src/main/kotlin/eu/mjdev/desktop/components/charts/DonutChart.kt
  24. 7 4
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/ControlCenter.kt
  25. 3 2
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/base/ControlCenterPage.kt
  26. 8 3
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/base/PageHeader.kt
  27. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/AIPage.kt
  28. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/BluetoothSettingsPage.kt
  29. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/Devices.kt
  30. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/DisplaySettingsPage.kt
  31. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/EthSettingsPage.kt
  32. 7 4
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/MainSettingsPage.kt
  33. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/SoundSettingsPage.kt
  34. 4 2
      src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/WifiSettingsPage.kt
  35. 12 10
      src/main/kotlin/eu/mjdev/desktop/components/custom/BrushedLayout.kt
  36. 8 1
      src/main/kotlin/eu/mjdev/desktop/components/custom/Clock.kt
  37. 8 1
      src/main/kotlin/eu/mjdev/desktop/components/custom/DateTime.kt
  38. 0 26
      src/main/kotlin/eu/mjdev/desktop/components/custom/MeasurableComponent.kt
  39. 30 17
      src/main/kotlin/eu/mjdev/desktop/components/custom/MeasureUnconstrainedView.kt
  40. 8 5
      src/main/kotlin/eu/mjdev/desktop/components/custom/PowerBlock.kt
  41. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/custom/VerticalScrollableBox.kt
  42. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/desktop/Desktop.kt
  43. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/desktop/widgets/MemoryChart.kt
  44. 5 1
      src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanel.kt
  45. 6 1
      src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelIcon.kt
  46. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelText.kt
  47. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelTray.kt
  48. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopMenuIcon.kt
  49. 5 1
      src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopPanelDateTime.kt
  50. 5 2
      src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopPanelFavoriteApps.kt
  51. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopPanelLanguage.kt
  52. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/draggable/DraggableView.kt
  53. 15 4
      src/main/kotlin/eu/mjdev/desktop/components/file/FolderIcon.kt
  54. 8 1
      src/main/kotlin/eu/mjdev/desktop/components/file/FolderView.kt
  55. 70 23
      src/main/kotlin/eu/mjdev/desktop/components/fonticon/FontIcon.kt
  56. 19 14
      src/main/kotlin/eu/mjdev/desktop/components/gallery/BoxWithControls.kt
  57. 21 14
      src/main/kotlin/eu/mjdev/desktop/components/gallery/Gallery.kt
  58. 8 4
      src/main/kotlin/eu/mjdev/desktop/components/gallery/ItemInfo.kt
  59. 10 2
      src/main/kotlin/eu/mjdev/desktop/components/greeter/Greeter.kt
  60. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/grid/GridPlaced.kt
  61. 8 1
      src/main/kotlin/eu/mjdev/desktop/components/guide/GuideView.kt
  62. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/icon/ShapedIcon.kt
  63. 13 7
      src/main/kotlin/eu/mjdev/desktop/components/icon/WifiLevelIcon.kt
  64. 5 1
      src/main/kotlin/eu/mjdev/desktop/components/image/GifView.kt
  65. 14 5
      src/main/kotlin/eu/mjdev/desktop/components/image/ImageAny.kt
  66. 5 1
      src/main/kotlin/eu/mjdev/desktop/components/image/ImageColoredBackground.kt
  67. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/image/PhotoImage.kt
  68. 5 1
      src/main/kotlin/eu/mjdev/desktop/components/immersivelist/ImmersiveList.kt
  69. 8 6
      src/main/kotlin/eu/mjdev/desktop/components/info/InfoWindow.kt
  70. 13 2
      src/main/kotlin/eu/mjdev/desktop/components/input/PasswordTextView.kt
  71. 9 2
      src/main/kotlin/eu/mjdev/desktop/components/input/SearchFieldPassive.kt
  72. 6 1
      src/main/kotlin/eu/mjdev/desktop/components/input/SelectableOutlineEditText.kt
  73. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/installer/Installer.kt
  74. 5 1
      src/main/kotlin/eu/mjdev/desktop/components/main/MainWindow.kt
  75. 7 2
      src/main/kotlin/eu/mjdev/desktop/components/menu/ContextMenu.kt
  76. 7 1
      src/main/kotlin/eu/mjdev/desktop/components/progress/DashedProgressIndicator.kt
  77. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/qrcode/QrCodeView.kt
  78. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/sliding/SlidingPanel.kt
  79. 9 1
      src/main/kotlin/eu/mjdev/desktop/components/surface/Surface.kt
  80. 4 5
      src/main/kotlin/eu/mjdev/desktop/components/surface/base/ClickableSurfaceGlow.kt
  81. 2 1
      src/main/kotlin/eu/mjdev/desktop/components/surface/base/SurfaceGlow.kt
  82. 18 3
      src/main/kotlin/eu/mjdev/desktop/components/text/AutoHideEmptyText.kt
  83. 10 2
      src/main/kotlin/eu/mjdev/desktop/components/text/AutoResizeText.kt
  84. 4 1
      src/main/kotlin/eu/mjdev/desktop/components/text/CircleText.kt
  85. 11 1
      src/main/kotlin/eu/mjdev/desktop/components/text/TextAny.kt
  86. 10 1
      src/main/kotlin/eu/mjdev/desktop/components/text/TextWithShadow.kt
  87. 8 1
      src/main/kotlin/eu/mjdev/desktop/components/tooltip/Tooltip.kt
  88. 63 32
      src/main/kotlin/eu/mjdev/desktop/components/user/UserAvatar.kt
  89. 6 1
      src/main/kotlin/eu/mjdev/desktop/components/video/VideoView.kt
  90. 5 1
      src/main/kotlin/eu/mjdev/desktop/components/web/ComposeWebView.kt
  91. 7 1
      src/main/kotlin/eu/mjdev/desktop/data/App.kt
  92. 15 0
      src/main/kotlin/eu/mjdev/desktop/data/ItemWithDate.kt
  93. 13 0
      src/main/kotlin/eu/mjdev/desktop/data/ItemWithTitle.kt
  94. 116 1
      src/main/kotlin/eu/mjdev/desktop/extensions/Compose.kt
  95. 1 1
      src/main/kotlin/eu/mjdev/desktop/icons/Icons.kt

+ 1 - 1
README.md

@@ -49,7 +49,7 @@ Build on compose kotlin and jvm.
 - import to intellij idea
 - click run or build (or select from run dialog what you want to do)
 
-# USed libraries
+# used libraries
 
 - [Jetbrains Compose Desktop] (https://github.com/JetBrains/compose-multiplatform)
   Main library for to made app

+ 1 - 1
build.gradle.kts

@@ -68,7 +68,7 @@ allprojects {
     dependencies {
         api(fileTree("src/main/libs") { include("*.jar") })
         // reflection
-//        implementation(kotlin("reflect"))
+        implementation(kotlin("reflect"))
         // coroutines
         runtimeOnly(libs.kotlinx.coroutines.swing)
         // compose desktop

+ 145 - 30
src/main/kotlin/eu/mjdev/desktop/components/appbar/AppBar.kt

@@ -16,7 +16,11 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.extensions.Compose.preview
+import eu.mjdev.desktop.extensions.Modifier.conditional
+import eu.mjdev.desktop.helpers.compose.Orientation
 
+// todo alignment scopes
 @Composable
 fun AppBar(
     modifier: Modifier = Modifier,
@@ -25,33 +29,69 @@ fun AppBar(
     iconVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
     titleVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
     actionsVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
+    titleHorizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
+    iconHorizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
+    actionsHorizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
     iconPadding: PaddingValues = PaddingValues(),
     titlePadding: PaddingValues = PaddingValues(),
     actionsPadding: PaddingValues = PaddingValues(),
+    orientation: Orientation = Orientation.Horizontal,
+    fillCenter: Boolean = true,
     icon: @Composable RowScope.() -> Unit = {},
     title: @Composable RowScope.() -> Unit = {},
     actions: @Composable RowScope.() -> Unit = {},
-) {
-    Row(
+) = when (orientation) {
+    Orientation.Horizontal -> Row(
+        modifier = modifier.wrapContentHeight().padding(contentPadding),
+        verticalAlignment = contentAlignment,
+    ) {
+        Row(
+            modifier = Modifier.wrapContentHeight().padding(iconPadding),
+            verticalAlignment = iconVerticalAlignment,
+            horizontalArrangement = iconHorizontalArrangement,
+            content = icon
+        )
+        Row(
+            modifier = Modifier
+                .conditional(fillCenter) {
+                    weight(1f)
+                }
+                .wrapContentHeight()
+                .padding(titlePadding),
+            verticalAlignment = titleVerticalAlignment,
+            horizontalArrangement = titleHorizontalArrangement,
+            content = title
+        )
+        Row(
+            modifier = Modifier.wrapContentHeight().padding(actionsPadding),
+            verticalAlignment = actionsVerticalAlignment,
+            horizontalArrangement = actionsHorizontalArrangement,
+            content = actions
+        )
+    }
+
+    Orientation.Vertical -> Column(
         modifier = modifier
-            .height(IntrinsicSize.Min)
+            .width(IntrinsicSize.Min)
             .padding(contentPadding),
-        verticalAlignment = contentAlignment,
     ) {
         Row(
-            modifier = Modifier.wrapContentHeight()
-                .padding(iconPadding),
+            modifier = Modifier.width(IntrinsicSize.Min).padding(iconPadding),
             verticalAlignment = iconVerticalAlignment,
             content = icon
         )
         Row(
-            modifier = Modifier.weight(1f).wrapContentHeight()
+            modifier = Modifier
+                .conditional(fillCenter) {
+                    weight(1f)
+                }
+                .wrapContentHeight()
                 .padding(titlePadding),
             verticalAlignment = titleVerticalAlignment,
             content = title
         )
         Row(
-            modifier = Modifier.wrapContentHeight()
+            modifier = Modifier.width(IntrinsicSize.Min)
                 .padding(actionsPadding),
             verticalAlignment = actionsVerticalAlignment,
             content = actions
@@ -61,25 +101,100 @@ fun AppBar(
 
 @Preview
 @Composable
-fun AppBarPreview() = AppBar(
-    modifier = Modifier.fillMaxWidth().height(48.dp).background(Color.Green),
-    icon = {
-        Box(
-            modifier = Modifier.size(24.dp)
-                .background(Color.Red)
-        )
-    },
-    title = {
-        Box(
-            modifier = Modifier.height(24.dp)
-                .fillMaxWidth()
-                .background(Color.Blue)
-        )
-    },
-    actions = {
-        Box(
-            modifier = Modifier.size(24.dp, 24.dp)
-                .background(Color.Yellow)
-        )
-    }
-)
+fun AppBarHorizontalPreview() = preview {
+    AppBar(
+        modifier = Modifier.height(48.dp).background(Color.Green),
+        orientation = Orientation.Horizontal,
+        fillCenter = false,
+        icon = {
+            Box(
+                modifier = Modifier.size(24.dp).background(Color.Red)
+            )
+        },
+        title = {
+            Box(
+                modifier = Modifier.size(24.dp).background(Color.Blue)
+            )
+        },
+        actions = {
+            Box(
+                modifier = Modifier.size(24.dp, 24.dp).background(Color.Yellow)
+            )
+        }
+    )
+}
+
+@Preview
+@Composable
+fun AppBarHorizontalFillPreview() = preview {
+    AppBar(
+        modifier = Modifier.height(48.dp).background(Color.Green),
+        orientation = Orientation.Horizontal,
+        fillCenter = true,
+        icon = {
+            Box(
+                modifier = Modifier.size(24.dp).background(Color.Red)
+            )
+        },
+        title = {
+            Box(
+                modifier = Modifier.height(24.dp).fillMaxWidth().background(Color.Blue)
+            )
+        },
+        actions = {
+            Box(
+                modifier = Modifier.size(24.dp, 24.dp).background(Color.Yellow)
+            )
+        }
+    )
+}
+
+@Preview
+@Composable
+fun AppBarVerticalPreview() = preview {
+    AppBar(
+        modifier = Modifier.background(Color.Green),
+        orientation = Orientation.Vertical,
+        fillCenter = false,
+        icon = {
+            Box(
+                modifier = Modifier.size(24.dp).background(Color.Red)
+            )
+        },
+        title = {
+            Box(
+                modifier = Modifier.size(24.dp).background(Color.Blue)
+            )
+        },
+        actions = {
+            Box(
+                modifier = Modifier.size(24.dp).background(Color.Yellow)
+            )
+        }
+    )
+}
+
+@Preview
+@Composable
+fun AppBarVerticalFillPreview() = preview {
+    AppBar(
+        modifier = Modifier.background(Color.Green),
+        orientation = Orientation.Vertical,
+        fillCenter = true,
+        icon = {
+            Box(
+                modifier = Modifier.size(24.dp).background(Color.Red)
+            )
+        },
+        title = {
+            Box(
+                modifier = Modifier.width(24.dp).fillMaxHeight().background(Color.Blue)
+            )
+        },
+        actions = {
+            Box(
+                modifier = Modifier.size(24.dp).background(Color.Yellow)
+            )
+        }
+    )
+}

+ 18 - 4
src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsBottomBar.kt

@@ -1,18 +1,24 @@
 package eu.mjdev.desktop.components.appsmenu
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
 import androidx.compose.foundation.focusable
-import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
 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.text.TextStyle
 import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import eu.mjdev.desktop.components.appbar.AppBar
 import eu.mjdev.desktop.components.icon.ShapedIcon
 import eu.mjdev.desktop.components.input.SearchFieldPassive
+import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
 import eu.mjdev.desktop.extensions.Compose.clear
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.icons.Icons
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
@@ -31,13 +37,17 @@ fun AppsBottomBar(
         modifier = modifier.focusable(false),
         title = {
             SearchFieldPassive(
-                modifier = Modifier.fillMaxWidth().focusable(true),
+                modifier = Modifier.padding(
+                    start = 8.dp,
+                    end = 8.dp
+                ).fillMaxWidth().focusable(true),
                 textState = searchTextState,
                 textColor = iconsTintColor,
                 textSize = 20.sp,
                 textStyle = TextStyle(
                     fontWeight = FontWeight.Bold
                 ),
+                backgroundColor = Color.Transparent,
                 onClearClick = { searchTextState.clear() }
             )
         },
@@ -53,7 +63,7 @@ fun AppsBottomBar(
             )
         },
         actions = {
-            AppActions(
+            AppsMenuActions(
                 onActionClick = onActionClick
             )
         }
@@ -62,4 +72,8 @@ fun AppsBottomBar(
 
 @Preview
 @Composable
-fun AppsBottomBarPreview() = AppsBottomBar()
+fun AppsBottomBarPreview() = preview {
+    AppsBottomBar(
+        modifier = Modifier.background(Color.SuperDarkGray)
+    )
+}

+ 4 - 7
src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsList.kt

@@ -23,6 +23,8 @@ import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.data.App
 import eu.mjdev.desktop.data.Category
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.helpers.compose.rememberForeverLazyListState
 import eu.mjdev.desktop.provider.DesktopScope
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
@@ -76,14 +78,9 @@ fun AppsList(
 
 @Preview
 @Composable
-fun AppsListPreview() {
+fun AppsListPreview() = preview(320, 640) {
     AppsList(
-        modifier = Modifier.padding(8.dp)
-            .background(
-                Color.Gray,
-                RoundedCornerShape(16.dp)
-            )
-            .padding(8.dp),
+        modifier = Modifier.background(Color.SuperDarkGray, RoundedCornerShape(16.dp)).padding(8.dp),
         items = listOf(App.Test, App.Test, App.Test)
     )
 }

+ 8 - 3
src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenu.kt

@@ -31,6 +31,7 @@ import eu.mjdev.desktop.extensions.Compose.clear
 import eu.mjdev.desktop.extensions.Compose.launchedEffect
 import eu.mjdev.desktop.extensions.Compose.onMouseEnter
 import eu.mjdev.desktop.extensions.Compose.plus
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberCalculated
 import eu.mjdev.desktop.extensions.Compose.rememberComputed
 import eu.mjdev.desktop.extensions.Compose.rememberState
@@ -40,6 +41,7 @@ import eu.mjdev.desktop.extensions.Custom.trimIsNotEmpty
 import eu.mjdev.desktop.extensions.Modifier.dropShadow
 import eu.mjdev.desktop.helpers.animation.Animations.AppsMenuEnterAnimation
 import eu.mjdev.desktop.helpers.animation.Animations.AppsMenuExitAnimation
+import eu.mjdev.desktop.helpers.compose.Orientation
 import eu.mjdev.desktop.helpers.compose.rememberForeverLazyListState
 import eu.mjdev.desktop.helpers.internal.KeyEventHandler.Companion.globalKeyEventHandler
 import eu.mjdev.desktop.helpers.shape.BarShape
@@ -188,11 +190,12 @@ fun AppsMenu(
                                 )
                         )
                         UserAvatar(
+                            avatarSize = 64.dp,
+                            orientation = Orientation.Horizontal,
                             titleVerticalAlignment = Alignment.Bottom,
                             iconPadding = PaddingValues(bottom = 16.dp),
                             titlePadding = PaddingValues(top = 24.dp, start = 20.dp),
-                            avatarSize = 64.dp,
-                            onUserAvatarClick = onUserAvatarClick
+                            onUserAvatarClick = onUserAvatarClick,
                         )
                     }
                     Divider(
@@ -267,4 +270,6 @@ fun AppsMenu(
 
 @Preview
 @Composable
-fun AppsMenuPreview() = AppsMenu()
+fun AppsMenuPreview() = preview {
+    AppsMenu()
+}

+ 12 - 2
src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppActions.kt → src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenuActions.kt

@@ -9,14 +9,20 @@
 package eu.mjdev.desktop.components.appsmenu
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentWidth
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.icon.ShapedIcon
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.runAsync
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
 import eu.mjdev.desktop.icons.Icons
@@ -24,7 +30,7 @@ import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import kotlinx.coroutines.Dispatchers
 
 @Composable
-fun AppActions(
+fun AppsMenuActions(
     // todo theme
     iconRestart: ImageVector = Icons.RestartComputer,
     // todo theme
@@ -84,4 +90,8 @@ fun AppActions(
 
 @Preview
 @Composable
-fun AppActionsPreview() = AppActions()
+fun AppsMenuActionsPreview() = preview {
+    AppsMenuActions(
+        modifier = Modifier.background(Color.SuperDarkGray, RoundedCornerShape(16.dp)).padding(8.dp),
+    )
+}

+ 13 - 9
src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenuApp.kt

@@ -15,9 +15,11 @@ import androidx.compose.ui.unit.*
 import eu.mjdev.desktop.components.fonticon.FontIcon
 import eu.mjdev.desktop.components.text.TextAny
 import eu.mjdev.desktop.data.App
+import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
 import eu.mjdev.desktop.extensions.Compose.onLeftClick
 import eu.mjdev.desktop.extensions.Compose.onMousePress
 import eu.mjdev.desktop.extensions.Compose.onRightClick
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
 import eu.mjdev.desktop.helpers.shape.DottedShape
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
@@ -93,12 +95,14 @@ fun AppsMenuApp(
 
 @Preview
 @Composable
-fun AppsMenuAppPreview() = AppsMenuApp(
-    modifier = Modifier.padding(8.dp)
-        .background(
-            Color.Gray,
-            RoundedCornerShape(16.dp)
-        )
-        .padding(8.dp),
-    app = App.Test
-)
+fun AppsMenuAppPreview() = preview {
+    AppsMenuApp(
+        modifier = Modifier.padding(8.dp)
+            .background(
+                Color.SuperDarkGray,
+                RoundedCornerShape(16.dp)
+            )
+            .padding(8.dp),
+        app = App.Test
+    )
+}

+ 13 - 9
src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenuCategory.kt

@@ -15,9 +15,11 @@ import androidx.compose.ui.unit.*
 import eu.mjdev.desktop.components.fonticon.FontIcon
 import eu.mjdev.desktop.components.text.TextAny
 import eu.mjdev.desktop.data.Category
+import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
 import eu.mjdev.desktop.extensions.Compose.onLeftClick
 import eu.mjdev.desktop.extensions.Compose.onMousePress
 import eu.mjdev.desktop.extensions.Compose.onRightClick
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
 import eu.mjdev.desktop.helpers.shape.DottedShape
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
@@ -80,12 +82,14 @@ fun AppsMenuCategory(
 
 @Preview
 @Composable
-fun AppsMenuCategoryPreview() = AppsMenuCategory(
-    modifier = Modifier.padding(8.dp)
-        .background(
-            Color.Gray,
-            RoundedCornerShape(16.dp)
-        )
-        .padding(8.dp),
-    category = Category("Audio")
-)
+fun AppsMenuCategoryPreview() = preview {
+    AppsMenuCategory(
+        modifier = Modifier.padding(8.dp)
+            .background(
+                Color.SuperDarkGray,
+                RoundedCornerShape(16.dp)
+            )
+            .padding(8.dp),
+        category = Category("Audio")
+    )
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/background/BackgroundImage.kt

@@ -13,6 +13,7 @@ import eu.mjdev.desktop.extensions.ColorUtils.alpha
 import eu.mjdev.desktop.extensions.Compose.Crossfade
 import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
 import eu.mjdev.desktop.extensions.Compose.launchedEffect
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.helpers.internal.Queue
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import kotlinx.coroutines.Dispatchers
@@ -70,4 +71,6 @@ fun BackgroundImage(
 
 @Preview
 @Composable
-fun BackgroundImagePreview() = BackgroundImage()
+fun BackgroundImagePreview() = preview {
+    BackgroundImage()
+}

+ 8 - 4
src/main/kotlin/eu/mjdev/desktop/components/blur/BlurPanel.kt

@@ -10,7 +10,10 @@ package eu.mjdev.desktop.components.blur
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.BoxScope
+import androidx.compose.foundation.layout.BoxWithConstraints
+import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -25,6 +28,7 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.image.ImageAny
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 // todo real blur
@@ -74,6 +78,6 @@ fun BlurPanel(
 
 @Preview
 @Composable
-fun BlurPanelPreview() = BlurPanel(
-    modifier = Modifier.size(480.dp, 800.dp)
-)
+fun BlurPanelPreview() = preview(480, 800) {
+    BlurPanel()
+}

+ 2 - 9
src/main/kotlin/eu/mjdev/desktop/components/button/ButtonPrimary.kt

@@ -1,16 +1,11 @@
 package eu.mjdev.desktop.components.button
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.material.Button
 import androidx.compose.material.ButtonDefaults
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
 import eu.mjdev.desktop.components.text.TextAny
-import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 @Composable
@@ -39,8 +34,6 @@ fun ButtonPrimary(
 
 @Preview
 @Composable
-fun ButtonPrimaryPreview() = Box(
-    modifier = Modifier.fillMaxSize().background(Color.SuperDarkGray)
-) {
+fun ButtonPrimaryPreview() = preview {
     ButtonPrimary()
 }

+ 2 - 9
src/main/kotlin/eu/mjdev/desktop/components/button/ButtonSecondary.kt

@@ -1,16 +1,11 @@
 package eu.mjdev.desktop.components.button
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.material.Button
 import androidx.compose.material.ButtonDefaults
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
 import eu.mjdev.desktop.components.text.TextAny
-import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 // todo
@@ -40,8 +35,6 @@ fun ButtonSecondary(
 
 @Preview
 @Composable
-fun ButtonSecondaryPreview() = Box(
-    modifier = Modifier.fillMaxSize().background(Color.SuperDarkGray)
-) {
+fun ButtonSecondaryPreview() = preview {
     ButtonSecondary()
 }

+ 2 - 7
src/main/kotlin/eu/mjdev/desktop/components/button/TransparentButton.kt

@@ -9,11 +9,8 @@
 package eu.mjdev.desktop.components.button
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.RowScope
-import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.material.Button
 import androidx.compose.material.ButtonDefaults
 import androidx.compose.material.Icon
@@ -21,8 +18,8 @@ import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
-import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
 import eu.mjdev.desktop.extensions.Compose.noElevation
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.transparent
 import eu.mjdev.desktop.icons.Icons
 
@@ -42,9 +39,7 @@ fun TransparentButton(
 
 @Preview
 @Composable
-fun TransparentButtonPreview() = Box(
-    modifier = Modifier.fillMaxSize().background(Color.SuperDarkGray)
-) {
+fun TransparentButtonPreview() = preview {
     TransparentButton {
         Icon(
             imageVector = Icons.User,

+ 16 - 1
src/main/kotlin/eu/mjdev/desktop/components/card/Card.kt

@@ -12,8 +12,11 @@ import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.card.base.*
 import eu.mjdev.desktop.components.card.base.CardDefaults.toClickableSurfaceBorder
 import eu.mjdev.desktop.components.card.base.CardDefaults.toClickableSurfaceColors
@@ -21,7 +24,10 @@ import eu.mjdev.desktop.components.card.base.CardDefaults.toClickableSurfaceGlow
 import eu.mjdev.desktop.components.card.base.CardDefaults.toClickableSurfaceScale
 import eu.mjdev.desktop.components.card.base.CardDefaults.toClickableSurfaceShape
 import eu.mjdev.desktop.components.surface.Surface
+import eu.mjdev.desktop.components.surface.base.Glow
+import eu.mjdev.desktop.extensions.Compose.preview
 
+// todo, card like in android tv
 @Composable
 fun Card(
     onClick: () -> Unit = {},
@@ -50,4 +56,13 @@ fun Card(
 
 @Preview
 @Composable
-fun CardPreview() = Card()
+fun CardPreview() = preview {
+    Card(
+        modifier = Modifier.size(200.dp, 128.dp),
+        colors = CardDefaults.colors(
+            containerColor = Color.White
+        ),
+        border = CardDefaults.border(2.dp),
+        glow = CardDefaults.glow(glow = Glow(Color.Green, 4.dp))
+    )
+}

+ 48 - 5
src/main/kotlin/eu/mjdev/desktop/components/card/ClassicCard.kt

@@ -13,9 +13,16 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.*
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.card.base.*
+import eu.mjdev.desktop.components.image.ImageAny
+import eu.mjdev.desktop.components.surface.base.Glow
+import eu.mjdev.desktop.components.text.TextAny
+import eu.mjdev.desktop.extensions.Compose.preview
+import eu.mjdev.desktop.icons.Icons
 
-@Suppress("unused")
+// todo
 @Composable
 fun ClassicCard(
     onClick: () -> Unit = {},
@@ -43,12 +50,48 @@ fun ClassicCard(
     border = border,
     glow = glow
 ) {
-    Column(modifier = Modifier.padding(contentPadding)) {
-        Box(contentAlignment = CardDefaults.ContentImageAlignment, content = image)
-        Column { CardContent(title = title, subtitle = subtitle, description = description) }
+    Column(
+        modifier = Modifier.padding(contentPadding)
+    ) {
+        Box(
+            contentAlignment = CardDefaults.ContentImageAlignment,
+            content = image
+        )
+        Column {
+            CardContent(
+                title = title,
+                subtitle = subtitle,
+                description = description
+            )
+        }
     }
 }
 
 @Preview
 @Composable
-fun ClassicCardPreview() = ClassicCard()
+fun ClassicCardPreview() = preview {
+    ClassicCard(
+        colors = CardDefaults.colors(
+            containerColor = Color.White
+        ),
+        border = CardDefaults.border(2.dp),
+        glow = CardDefaults.glow(glow = Glow(Color.Green, 4.dp)),
+        contentPadding = PaddingValues(8.dp),
+        scale = CardDefaults.scale(1f),
+        image = {
+            ImageAny(
+                src = Icons.User,
+                contentDescription = ""
+            )
+        },
+        title = {
+            TextAny("title")
+        },
+        subtitle = {
+            TextAny("subtitle")
+        },
+        description = {
+            TextAny("description")
+        }
+    )
+}

+ 78 - 28
src/main/kotlin/eu/mjdev/desktop/components/card/CompactCard.kt

@@ -10,9 +10,7 @@ package eu.mjdev.desktop.components.card
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.BoxScope
-import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.*
 import androidx.compose.material.MaterialTheme
 import androidx.compose.material.ProvideTextStyle
 import androidx.compose.runtime.Composable
@@ -20,11 +18,19 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.drawWithCache
 import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.card.base.*
 import eu.mjdev.desktop.components.card.base.CardDefaults.DescriptionAlpha
 import eu.mjdev.desktop.components.card.base.CardDefaults.SubtitleAlpha
+import eu.mjdev.desktop.components.image.ImageAny
+import eu.mjdev.desktop.components.surface.base.Glow
+import eu.mjdev.desktop.components.text.TextAny
+import eu.mjdev.desktop.extensions.Compose.preview
+import eu.mjdev.desktop.icons.Icons
 
+// todo
 @Composable
 fun CompactCard(
     onClick: () -> Unit = {},
@@ -41,31 +47,36 @@ fun CompactCard(
     glow: CardGlow = CardDefaults.glow(),
     scrimBrush: Brush = CardDefaults.ScrimBrush,
     interactionSource: MutableInteractionSource? = null
+) = Card(
+    onClick = onClick,
+    onLongClick = onLongClick,
+    modifier = modifier,
+    interactionSource = interactionSource,
+    shape = shape,
+    colors = colors,
+    scale = scale,
+    border = border,
+    glow = glow
 ) {
-    Card(
-        onClick = onClick,
-        onLongClick = onLongClick,
-        modifier = modifier,
-        interactionSource = interactionSource,
-        shape = shape,
-        colors = colors,
-        scale = scale,
-        border = border,
-        glow = glow
+    Box(
+        contentAlignment = Alignment.BottomStart
     ) {
-        Box(contentAlignment = Alignment.BottomStart) {
-            Box(
-                modifier =
-                    Modifier.drawWithCache {
-                        onDrawWithContent {
-                            drawContent()
-                            drawRect(brush = scrimBrush)
-                        }
-                    },
-                contentAlignment = CardDefaults.ContentImageAlignment,
-                content = image
+        Box(
+            modifier = Modifier.drawWithCache {
+                onDrawWithContent {
+                    drawContent()
+                    drawRect(brush = scrimBrush)
+                }
+            },
+            contentAlignment = CardDefaults.ContentImageAlignment,
+            content = image
+        )
+        Column {
+            CardContent(
+                title = title,
+                subtitle = subtitle,
+                description = description
             )
-            Column { CardContent(title = title, subtitle = subtitle, description = description) }
         }
     }
 }
@@ -75,7 +86,7 @@ fun CardContent(
     title: @Composable () -> Unit = {},
     subtitle: @Composable () -> Unit = {},
     description: @Composable () -> Unit = {}
-) {
+) = Column {
     ProvideTextStyle(MaterialTheme.typography.subtitle2) {
         title()
     }
@@ -101,8 +112,47 @@ fun CardContent(
 
 @Preview
 @Composable
-fun CardContentPreview() = CardContent()
+fun CardContentPreview() = preview {
+    CardContent(
+        title = {
+            TextAny("title")
+        },
+        subtitle = {
+            TextAny("subtitle")
+        },
+        description = {
+            TextAny("description")
+        }
+    )
+}
 
 @Preview
 @Composable
-fun CompactCardPreview() = CompactCard()
+fun CompactCardPreview() = preview {
+    CompactCard(
+        modifier = Modifier.size(200.dp, 128.dp),
+        colors = CardDefaults.colors(
+            containerColor = Color.White
+        ),
+        border = CardDefaults.border(),
+        glow = CardDefaults.glow(glow = Glow(Color.Green, 4.dp)),
+        scale = CardDefaults.scale(1f),
+        scrimBrush = CardDefaults.ScrimBrush,
+        image = {
+            ImageAny(
+                modifier = Modifier.fillMaxSize(),
+                src = Icons.User,
+                contentDescription = ""
+            )
+        },
+        title = {
+            TextAny("title")
+        },
+        subtitle = {
+            TextAny("subtitle")
+        },
+        description = {
+            TextAny("description")
+        }
+    )
+}

+ 33 - 17
src/main/kotlin/eu/mjdev/desktop/components/card/FocusableCard.kt

@@ -27,18 +27,22 @@ import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.card.base.*
+import eu.mjdev.desktop.components.card.base.CardDefaults.HorizontalImageAspectRatio
 import eu.mjdev.desktop.components.card.base.CardDefaults.colorFocusBorder
 import eu.mjdev.desktop.components.card.base.CardDefaults.colorFocusGlow
 import eu.mjdev.desktop.components.image.ImageAny
+import eu.mjdev.desktop.components.surface.base.Glow
 import eu.mjdev.desktop.components.text.AutoHideEmptyText
 import eu.mjdev.desktop.components.text.TextAny
 import eu.mjdev.desktop.extensions.Compose.focusState
 import eu.mjdev.desktop.extensions.Compose.isFocused
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberFocusRequester
 import eu.mjdev.desktop.extensions.Compose.rememberFocusState
 import eu.mjdev.desktop.extensions.Compose.requestFocusOnTouch
 import eu.mjdev.desktop.helpers.compose.FocusHelper
 
+// todo
 @Composable
 fun FocusableCard(
     item: Any? = null,
@@ -92,26 +96,23 @@ fun FocusableCard(
     colors = colors,
     border = border,
     glow = glow,
-    modifier = modifier
-        .size(
-            width = cardWidth,
-            height = cardWidth / aspectRatio
-        )
-        .focusState(focusState)
-        .onFocusChanged { state ->
-            onFocusChange(state)
-        }
-        .requestFocusOnTouch(focusRequester) {
-            if (focusState.isFocused) onClick?.invoke(item)
-        },
+    modifier = modifier.size(
+        width = cardWidth,
+        height = cardWidth / aspectRatio
+    ).focusState(
+        focusState
+    ).onFocusChanged { state ->
+        onFocusChange(state)
+    }.requestFocusOnTouch(focusRequester) {
+        if (focusState.isFocused) onClick?.invoke(item)
+    },
     image = {
         imageRenderer()
     },
     title = {
         if (showTitle) {
             Box(
-                modifier = Modifier
-                    .fillMaxWidth()
+                modifier = Modifier.fillMaxWidth()
                     .background(
                         if (focusState.isFocused) textBackgroundSelected
                         else textBackgroundUnselected,
@@ -131,8 +132,7 @@ fun FocusableCard(
     subtitle = {
         if (showTitle) {
             Box(
-                modifier = Modifier
-                    .fillMaxWidth()
+                modifier = Modifier.fillMaxWidth()
                     .background(
                         if (focusState.isFocused)
                             textBackgroundSelected
@@ -161,4 +161,20 @@ fun FocusableCard(
 
 @Preview
 @Composable
-fun FocusableCardPreview() = FocusableCard()
+fun FocusableCardPreview() = preview {
+    FocusableCard(
+        item = "test",
+        modifier = Modifier.size(200.dp, 128.dp),
+        colors = CardDefaults.colors(
+            containerColor = Color.White
+        ),
+        border = CardDefaults.border(),
+        glow = CardDefaults.glow(glow = Glow(Color.Green, 4.dp)),
+        scale = CardDefaults.scale(1f),
+        contentScale = ContentScale.Crop,
+        textColor = Color.Black,
+        showTitle = true,
+        focused = true,
+        aspectRatio = HorizontalImageAspectRatio,
+    )
+}

+ 21 - 1
src/main/kotlin/eu/mjdev/desktop/components/card/ItemCard.kt

@@ -12,6 +12,7 @@ import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.BrokenImage
 import androidx.compose.runtime.Composable
@@ -24,9 +25,12 @@ import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.card.base.*
+import eu.mjdev.desktop.components.card.base.CardDefaults.HorizontalImageAspectRatio
 import eu.mjdev.desktop.components.card.base.CardDefaults.colorFocusBorder
 import eu.mjdev.desktop.components.card.base.CardDefaults.colorFocusGlow
 import eu.mjdev.desktop.components.image.ImageAny
+import eu.mjdev.desktop.components.surface.base.Glow
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberFocusRequester
 import eu.mjdev.desktop.extensions.Compose.rememberFocusState
 import eu.mjdev.desktop.helpers.compose.FocusHelper
@@ -95,4 +99,20 @@ fun ItemCard(
 
 @Preview
 @Composable
-fun ItemCardPreview() = ItemCard()
+fun ItemCardPreview() = preview {
+    ItemCard(
+        item = "test",
+        modifier = Modifier.size(200.dp, 128.dp),
+        colors = CardDefaults.colors(
+            containerColor = Color.White
+        ),
+        border = CardDefaults.border(),
+        glow = CardDefaults.glow(glow = Glow(Color.Green, 4.dp)),
+        scale = CardDefaults.scale(1f),
+        contentScale = ContentScale.Crop,
+        textColor = Color.Black,
+        showTitle = true,
+        focused = true,
+        aspectRatio = HorizontalImageAspectRatio,
+    )
+}

+ 36 - 27
src/main/kotlin/eu/mjdev/desktop/components/card/PhotoCard.kt

@@ -4,6 +4,7 @@ import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.MutableState
 import androidx.compose.ui.Modifier
@@ -14,10 +15,12 @@ import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.card.base.CardDefaults
+import eu.mjdev.desktop.components.card.base.CardDefaults.HorizontalImageAspectRatio
 import eu.mjdev.desktop.components.card.base.CardScale
 import eu.mjdev.desktop.components.image.ImageAny
 import eu.mjdev.desktop.components.image.PhotoImage
 import eu.mjdev.desktop.extensions.Compose.isFocused
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberFocusRequester
 import eu.mjdev.desktop.extensions.Compose.rememberFocusState
 import eu.mjdev.desktop.helpers.compose.FocusHelper
@@ -64,38 +67,44 @@ fun PhotoCard(
     titlePadding: PaddingValues = PaddingValues(8.dp),
     onFocus: ((item: Any?, fromUser: Boolean) -> Unit)? = null,
     onClick: ((item: Any?) -> Unit)? = null,
-) {
-    ItemCard(
-        item = item,
-        modifier = modifier,
-        contentScale = contentScale,
-        textColor = textColor,
-        focusState = focusState,
-        focusRequester = focusRequester,
-        focused = focused,
-        aspectRatio = aspectRatio,
-        cardWidth = cardWidth,
-        scale = scale,
-        imageRenderer = imageRenderer,
-        titlePadding = titlePadding,
-        onFocus = onFocus,
-        onClick = onClick,
-        showTitle = showTitle
-    )
-}
+) = ItemCard(
+    item = item,
+    modifier = modifier,
+    contentScale = contentScale,
+    textColor = textColor,
+    focusState = focusState,
+    focusRequester = focusRequester,
+    focused = focused,
+    aspectRatio = aspectRatio,
+    cardWidth = cardWidth,
+    scale = scale,
+    imageRenderer = imageRenderer,
+    titlePadding = titlePadding,
+    onFocus = onFocus,
+    onClick = onClick,
+    showTitle = showTitle
+)
 
 @Composable
 fun computeCardWidth(
     api: DesktopProvider = LocalDesktop.current,
     ratio: Float = 2.5f
-): Dp =
-//    LocalConfiguration.current.let { config ->
-//    if (config.orientation == Configuration.ORIENTATION_PORTRAIT)
-    api.containerSize.width / ratio
-//    else
-//        config.screenHeightDp / ratio
-//}.dp
+): Dp {
+    return if (api.containerSize.let { it.height > it.width }) api.containerSize.width / ratio
+    else api.containerSize.height / ratio
+}
 
 @Preview
 @Composable
-fun PhotoCardPreview() = PhotoCard()
+fun PhotoCardPreview() = preview {
+    PhotoCard(
+        item = "test",
+        modifier = Modifier.size(200.dp, 128.dp),
+        scale = CardDefaults.scale(1f),
+        contentScale = ContentScale.Crop,
+        textColor = Color.Black,
+        showTitle = true,
+        focused = true,
+        aspectRatio = HorizontalImageAspectRatio,
+    )
+}

+ 46 - 16
src/main/kotlin/eu/mjdev/desktop/components/card/WideClassicCard.kt

@@ -13,7 +13,14 @@ import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.*
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.card.base.*
+import eu.mjdev.desktop.components.image.ImageAny
+import eu.mjdev.desktop.components.surface.base.Glow
+import eu.mjdev.desktop.components.text.TextAny
+import eu.mjdev.desktop.extensions.Compose.preview
+import eu.mjdev.desktop.icons.Icons
 
 @Suppress("unused")
 @Composable
@@ -32,25 +39,48 @@ fun WideClassicCard(
     glow: CardGlow = CardDefaults.glow(),
     contentPadding: PaddingValues = PaddingValues(),
     interactionSource: MutableInteractionSource? = null
+) = Card(
+    onClick = onClick,
+    onLongClick = onLongClick,
+    modifier = modifier,
+    interactionSource = interactionSource,
+    shape = shape,
+    colors = colors,
+    scale = scale,
+    border = border,
+    glow = glow
 ) {
-    Card(
-        onClick = onClick,
-        onLongClick = onLongClick,
-        modifier = modifier,
-        interactionSource = interactionSource,
-        shape = shape,
-        colors = colors,
-        scale = scale,
-        border = border,
-        glow = glow
-    ) {
-        Row(modifier = Modifier.padding(contentPadding)) {
-            Box(contentAlignment = CardDefaults.ContentImageAlignment, content = image)
-            Column { CardContent(title = title, subtitle = subtitle, description = description) }
-        }
+    Row(modifier = Modifier.padding(contentPadding)) {
+        Box(contentAlignment = CardDefaults.ContentImageAlignment, content = image)
+        Column { CardContent(title = title, subtitle = subtitle, description = description) }
     }
 }
 
 @Preview
 @Composable
-fun WideClassicCardPreview() = WideClassicCard()
+fun WideClassicCardPreview() = preview {
+    WideClassicCard(
+        colors = CardDefaults.colors(
+            containerColor = Color.White
+        ),
+        border = CardDefaults.border(),
+        glow = CardDefaults.glow(glow = Glow(Color.Green, 4.dp)),
+        contentPadding = PaddingValues(8.dp),
+        scale = CardDefaults.scale(1f),
+        image = {
+            ImageAny(
+                src = Icons.User,
+                contentDescription = ""
+            )
+        },
+        title = {
+            TextAny("title")
+        },
+        subtitle = {
+            TextAny("subtitle")
+        },
+        description = {
+            TextAny("description")
+        }
+    )
+}

+ 26 - 7
src/main/kotlin/eu/mjdev/desktop/components/card/base/CardDefaults.kt

@@ -105,13 +105,13 @@ object CardDefaults {
             ),
             shape = RoundedCornerShape(roundCornerSize)
         ),
-    pressedBorder = Border(
-        border = BorderStroke(
-            width = width,
-            color = colorPressed
-        ),
-        shape = RoundedCornerShape(roundCornerSize)
-    )
+        pressedBorder = Border(
+            border = BorderStroke(
+                width = width,
+                color = colorPressed
+            ),
+            shape = RoundedCornerShape(roundCornerSize)
+        )
     )
 
     @Composable
@@ -155,6 +155,25 @@ object CardDefaults {
         pressedBorder = pressedBorder
     )
 
+    @ReadOnlyComposable
+    @Composable
+    fun border(
+        borderWidth: Dp,
+        borderColor: Color = Color.Black,
+        border: Border = Border(
+            border = BorderStroke(width = borderWidth, color = borderColor)
+        ),
+        focusedBorder: Border = Border(
+            border = BorderStroke(width = borderWidth + 2.dp, color = borderColor), // todo theme
+            shape = ContainerShape
+        ),
+        pressedBorder: Border = focusedBorder
+    ) = CardBorder(
+        border = border,
+        focusedBorder = focusedBorder,
+        pressedBorder = pressedBorder
+    )
+
     fun glow(
         glow: Glow = Glow.None,
         focusedGlow: Glow = glow,

+ 18 - 8
src/main/kotlin/eu/mjdev/desktop/components/charts/DonutChart.kt

@@ -10,6 +10,7 @@ import androidx.compose.ui.text.TextStyle
 import com.aay.compose.baseComponents.model.LegendPosition
 import com.aay.compose.donutChart.DonutChart
 import com.aay.compose.donutChart.model.PieChartData
+import eu.mjdev.desktop.extensions.Compose.preview
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.isActive
 
@@ -64,13 +65,22 @@ fun DonutChart(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun DonutChartPreview() = DonutChart(
-    dataHandler = {
-        listOf(
-            PieChartData(0.4, Color.Blue, "test1"),
-            PieChartData(0.4, Color.Gray, "test1")
-        )
-    }
-)
+fun DonutChartPreview() = preview(480) {
+    DonutChart(
+        textColor = Color.White,
+        outerCircularColor = Color.White,
+        innerCircularColor = Color.White,
+        ratioLineColor = Color.White,
+        title = "Donut Chart",
+        legendPosition = LegendPosition.BOTTOM,
+        dataHandler = {
+            listOf(
+                PieChartData(24.0, Color.Blue, "test1"),
+                PieChartData(32.0, Color.Gray, "test2")
+            )
+        }
+    )
+}

+ 7 - 4
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/ControlCenter.kt

@@ -20,16 +20,17 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.platform.isDebugInspectorInfoEnabled
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.WindowPosition
 import eu.mjdev.desktop.components.blur.BlurPanel
-import eu.mjdev.desktop.components.controlcenter.base.PageHeader
 import eu.mjdev.desktop.components.sliding.SlidingPanel
 import eu.mjdev.desktop.extensions.Compose.onLeftClick
 import eu.mjdev.desktop.extensions.Compose.onMousePress
 import eu.mjdev.desktop.extensions.Compose.onRightClick
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberCalculated
 import eu.mjdev.desktop.extensions.Compose.rememberComputed
 import eu.mjdev.desktop.extensions.Compose.rememberState
@@ -46,7 +47,7 @@ import eu.mjdev.desktop.windows.ChromeWindowState.Companion.rememberChromeWindow
 @Composable
 fun ControlCenter(
     pagerState: MutableState<Int> = rememberState(0),
-    controlCenterState: ChromeWindowState = rememberChromeWindowState(),
+    controlCenterState: ChromeWindowState = rememberChromeWindowState(visible = isDebugInspectorInfoEnabled),
     enterAnimation: EnterTransition = ControlCenterEnterAnimation,
     exitAnimation: ExitTransition = ControlCenterExitAnimation,
     onFocusChange: ChromeWindowState.(Boolean) -> Unit = {},
@@ -184,7 +185,6 @@ fun ControlCenter(
                                         modifier = Modifier.width(controlCenterExpandedWidth),
                                     ) {
                                         val page = pagesFiltered.value[pagerState.value]
-                                        PageHeader(page = page)
                                         Box(modifier = Modifier.weight(1f)) {
                                             page.render()
                                         }
@@ -210,6 +210,9 @@ fun ControlCenter(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun ControlCenterPreview() = ControlCenter()
+fun ControlCenterPreview() = preview {
+    ControlCenter()
+}

+ 3 - 2
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/base/ControlCenterPage.kt

@@ -1,7 +1,7 @@
 package eu.mjdev.desktop.components.controlcenter.base
 
 import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Settings
@@ -26,9 +26,10 @@ class ControlCenterPage(
     fun render() = withControlCenterPageScope(
         cache = cache
     ) {
-        Row(
+        Column(
             modifier = Modifier.fillMaxSize()
         ) {
+            PageHeader(page = this@ControlCenterPage)
             Box(
                 modifier = Modifier.weight(1f),
             ) {

+ 8 - 3
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/base/PageHeader.kt

@@ -18,9 +18,10 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import eu.mjdev.desktop.components.appbar.AppBar
-import eu.mjdev.desktop.components.controlcenter.pages.MainSettingsPage
+import eu.mjdev.desktop.components.controlcenter.pages.WifiSettingsPage
 import eu.mjdev.desktop.components.image.ImageAny
 import eu.mjdev.desktop.components.text.TextAny
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
 import eu.mjdev.desktop.extensions.Modifier.clipCircle
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
@@ -28,7 +29,7 @@ import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 @Composable
 fun PageHeader(
     modifier: Modifier = Modifier,
-    page: ControlCenterPage = MainSettingsPage(),
+    page: ControlCenterPage,
     contentPadding: PaddingValues = PaddingValues(8.dp),
     iconSize: Dp = 64.dp,
     actions: @Composable RowScope.() -> Unit = {},
@@ -68,4 +69,8 @@ fun PageHeader(
 
 @Preview
 @Composable
-fun PageHeaderPreview() = PageHeader()
+fun PageHeaderPreview() = preview {
+    PageHeader(
+        page = WifiSettingsPage()
+    )
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/AIPage.kt

@@ -26,6 +26,7 @@ import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
 import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPageScope.Companion.remember
 import eu.mjdev.desktop.components.input.SelectableOutlineEditText
 import eu.mjdev.desktop.components.text.TextAny
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.extensions.Compose.scrollWithAnimToLast
 import eu.mjdev.desktop.extensions.Compose.verticalTouchScrollable
@@ -204,4 +205,6 @@ fun TextBlock(
 
 @Preview
 @Composable
-fun AIPagePreview() = AIPage().render()
+fun AIPagePreview() = preview {
+    AIPage().render()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/BluetoothSettingsPage.kt

@@ -8,6 +8,7 @@ import androidx.compose.material.icons.filled.Bluetooth
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Suppress("FunctionName")
 fun BluetoothSettingsPage() = ControlCenterPage(
@@ -22,4 +23,6 @@ fun BluetoothSettingsPage() = ControlCenterPage(
 
 @Preview
 @Composable
-fun BluetoothSettingsPagePreview() =  BluetoothSettingsPage().render()
+fun BluetoothSettingsPagePreview() = preview {
+    BluetoothSettingsPage().render()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/Devices.kt

@@ -8,6 +8,7 @@ import androidx.compose.material.icons.filled.MobileFriendly
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Suppress("FunctionName")
 fun DevicesPage() = ControlCenterPage(
@@ -23,4 +24,6 @@ fun DevicesPage() = ControlCenterPage(
 
 @Preview
 @Composable
-fun DevicesPagePreview() =  DevicesPage().render()
+fun DevicesPagePreview() = preview {
+    DevicesPage().render()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/DisplaySettingsPage.kt

@@ -8,6 +8,7 @@ import androidx.compose.material.icons.filled.ScreenshotMonitor
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Suppress("FunctionName")
 fun DisplaySettingsPage() = ControlCenterPage(
@@ -21,4 +22,6 @@ fun DisplaySettingsPage() = ControlCenterPage(
 
 @Preview
 @Composable
-fun DisplaySettingsPagePreview() =  DisplaySettingsPage().render()
+fun DisplaySettingsPagePreview() = preview {
+    DisplaySettingsPage().render()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/EthSettingsPage.kt

@@ -8,6 +8,7 @@ import androidx.compose.material.icons.filled.SettingsEthernet
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Suppress("FunctionName")
 fun EthSettingsPage() = ControlCenterPage(
@@ -22,4 +23,6 @@ fun EthSettingsPage() = ControlCenterPage(
 
 @Preview
 @Composable
-fun EthSettingsPagePreview() =  EthSettingsPage().render()
+fun EthSettingsPagePreview() = preview {
+    EthSettingsPage().render()
+}

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

@@ -20,7 +20,9 @@ import eu.mjdev.desktop.components.custom.PowerBlock
 import eu.mjdev.desktop.components.user.UserAvatar
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
 import eu.mjdev.desktop.extensions.ColorUtils.darker
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.runAsync
+import eu.mjdev.desktop.helpers.compose.Orientation
 import eu.mjdev.desktop.helpers.shape.BarShape
 
 @Suppress("FunctionName")
@@ -73,10 +75,10 @@ fun MainSettingsPage() = ControlCenterPage(
                     avatarSize = 96.dp,
                     titleTextSize = 20.sp,
                     detailTextSize = 16.sp,
-                    titleHorizontalAlignment = Alignment.CenterHorizontally,
                     onUserAvatarClick = {
                         // todo
-                    }
+                    },
+                    orientation = Orientation.Horizontal
                 )
             }
             Divider(
@@ -126,7 +128,6 @@ fun MainSettingsPage() = ControlCenterPage(
                     .align(Alignment.BottomCenter)
             ) {
                 PowerBlock(
-                    backgroundColor = backgroundColor,
                     shadowColor = borderColor.alpha(0.3f),
                     onPowerButtonClick = {
                         // todo : dialog
@@ -142,4 +143,6 @@ fun MainSettingsPage() = ControlCenterPage(
 
 @Preview
 @Composable
-fun MainSettingsPagePreview() = MainSettingsPage().render()
+fun MainSettingsPagePreview() = preview {
+    MainSettingsPage().render()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/SoundSettingsPage.kt

@@ -8,6 +8,7 @@ import androidx.compose.material.icons.filled.Headphones
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Suppress("FunctionName")
 fun SoundSettingsPage() = ControlCenterPage(
@@ -21,4 +22,6 @@ fun SoundSettingsPage() = ControlCenterPage(
 
 @Preview
 @Composable
-fun SoundSettingsPagePreview() = SoundSettingsPage().render()
+fun SoundSettingsPagePreview() = preview {
+    SoundSettingsPage().render()
+}

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

@@ -21,7 +21,7 @@ import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
 import eu.mjdev.desktop.components.icon.WifiLevelIcon
 import eu.mjdev.desktop.components.text.TextAny
 import eu.mjdev.desktop.data.WifiInfo
-import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Custom.flowBlock
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
@@ -107,4 +107,6 @@ fun WifiRow(
 
 @Preview
 @Composable
-fun WifiSettingsPagePreview() = WifiSettingsPage().render()
+fun WifiSettingsPagePreview() = preview {
+    WifiSettingsPage().render()
+}

+ 12 - 10
src/main/kotlin/eu/mjdev/desktop/components/custom/BrushedLayout.kt

@@ -14,6 +14,7 @@ import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Composable
 fun BrushedLayout(
@@ -21,16 +22,17 @@ fun BrushedLayout(
     alpha: Float = 1f,
     colorStart: Color = Color.Black.copy(alpha = if (alpha.isNaN()) 1f else alpha),
     colorEnd: Color = Color.Transparent,
-) {
-    val brush = Brush.radialGradient(listOf(colorStart, colorEnd))
-    Canvas(
-        modifier = modifier,
-        onDraw = {
-            drawRect(brush)
-        }
-    )
-}
+    brush: Brush = Brush.radialGradient(listOf(colorStart, colorEnd))
+) = Canvas(
+    modifier = modifier,
+    onDraw = {
+        drawRect(brush)
+    }
+)
 
+// todo
 @Preview
 @Composable
-fun BrushedLayoutPreview() = BrushedLayout()
+fun BrushedLayoutPreview() = preview(320) {
+    BrushedLayout()
+}

+ 8 - 1
src/main/kotlin/eu/mjdev/desktop/components/custom/Clock.kt

@@ -17,8 +17,10 @@ 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.preview
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.extensions.Compose.runAsync
+import eu.mjdev.desktop.extensions.Compose.size
 import eu.mjdev.desktop.extensions.Custom.ParsedList
 import eu.mjdev.desktop.extensions.Custom.dateFlow
 import eu.mjdev.desktop.extensions.Custom.timeFlow
@@ -92,6 +94,11 @@ fun Clock(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun ClockPreview() = Clock()
+fun ClockPreview() = preview {
+    Clock(
+        modifier = Modifier.size(320, 200)
+    )
+}

+ 8 - 1
src/main/kotlin/eu/mjdev/desktop/components/custom/DateTime.kt

@@ -12,6 +12,8 @@ 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.extensions.Compose.preview
+import eu.mjdev.desktop.extensions.Compose.size
 
 @Composable
 fun DateTime(
@@ -48,6 +50,11 @@ fun DateTime(
     )
 }
 
+// todo
 @Preview
 @Composable
-fun DateTimePreview() = DateTime()
+fun DateTimePreview() = preview {
+    DateTime(
+        modifier = Modifier.size(320, 200)
+    )
+}

+ 0 - 26
src/main/kotlin/eu/mjdev/desktop/components/custom/MeasurableComponent.kt

@@ -1,26 +0,0 @@
-package eu.mjdev.desktop.components.custom
-
-//import androidx.compose.runtime.Composable
-//import androidx.compose.ui.layout.SubcomposeLayout
-//import androidx.compose.ui.unit.DpSize
-//import androidx.compose.ui.unit.dp
-
-//@Suppress("FunctionName", "unused")
-//@Composable
-//fun MeasurableComponent(
-//    key: Any? = null,
-//    onMeasure: (size: DpSize) -> Unit = {},
-//    content: @Composable () -> Unit = {},
-//) = SubcomposeLayout { constraints ->
-//    subcompose(
-//        key,
-//        content
-//    ).map { measurable ->
-//        measurable.measure(constraints.copy(minWidth = 0, minHeight = 0))
-//    }.first().let { placeable ->
-//        onMeasure(DpSize(placeable.width.dp, placeable.height.dp))
-//        layout(placeable.width, placeable.height) {
-//            placeable.placeRelative(0, 0)
-//        }
-//    }
-//}

+ 30 - 17
src/main/kotlin/eu/mjdev/desktop/components/custom/MeasureUnconstrainedView.kt

@@ -1,35 +1,48 @@
 package eu.mjdev.desktop.components.custom
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
 import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.layout.SubcomposeLayout
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.text.TextAny
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Composable
 fun MeasureUnconstrainedView(
     viewToMeasure: @Composable () -> Unit,
     content: @Composable (DpSize) -> Unit,
-) {
-    SubcomposeLayout { constraints ->
-        val measured = subcompose("viewToMeasure", viewToMeasure)[0]
-            .measure(Constraints())
-        val measuredWidth = measured.width.toDp()
-        val measuredHeight = measured.height.toDp()
-        val contentPlaceable = subcompose("content") {
-            content(DpSize(measuredWidth, measuredHeight))
-        }[0].measure(constraints)
-        layout(contentPlaceable.width, contentPlaceable.height) {
-            contentPlaceable.place(0, 0)
-        }
+) = SubcomposeLayout { constraints ->
+    val measured = subcompose(
+        "viewToMeasure",
+        viewToMeasure
+    ).getOrNull(0)?.measure(Constraints())
+    val measuredWidth = measured?.width?.toDp() ?: 0.dp
+    val measuredHeight = measured?.height?.toDp() ?: 0.dp
+    val contentPlaceable = subcompose("content") {
+        content(DpSize(measuredWidth, measuredHeight))
+    }.getOrNull(0)?.measure(constraints)
+    layout(
+        contentPlaceable?.width ?: 0,
+        contentPlaceable?.height ?: 0
+    ) {
+        contentPlaceable?.place(0, 0)
     }
 }
 
 @Preview
 @Composable
-fun MeasureUnconstrainedViewPreview() = MeasureUnconstrainedView({
-    TextAny("test")
-}, { size ->
-    TextAny("test size: $size")
-})
+fun MeasureUnconstrainedViewPreview() = preview {
+    MeasureUnconstrainedView({
+        TextAny("test")
+    }, { size ->
+        TextAny(
+            modifier = Modifier.background(Color.White),
+            text = "test size: $size"
+        )
+    })
+}

+ 8 - 5
src/main/kotlin/eu/mjdev/desktop/components/custom/PowerBlock.kt

@@ -18,6 +18,7 @@ import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
 import eu.mjdev.desktop.extensions.Compose.noElevation
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.transparent
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
 import eu.mjdev.desktop.extensions.Modifier.circleShadow
@@ -28,14 +29,14 @@ import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 @Composable
 fun PowerBlock(
-    backgroundColor: Color = Color.Transparent,
+    modifier: Modifier = Modifier,
     shadowColor: Color = Color.Black.copy(alpha = 0.3f),
     bottomBoxHeight: Dp = 128.dp,
     iconHeight: Dp = 64.dp,
     onPowerButtonClick: () -> Unit = {}
 ) = withDesktopScope {
     Column(
-        modifier = Modifier.fillMaxWidth()
+        modifier = modifier.fillMaxWidth()
     ) {
         BoxWithConstraints(
             modifier = Modifier
@@ -53,7 +54,7 @@ fun PowerBlock(
                 modifier = Modifier
                     .fillMaxWidth()
                     .height(iconHeight)
-                    .rectShadow(color = shadowColor)
+                    .rectShadow(color = shadowColor, shape = shape)
                     .background(backgroundColor, shape)
             )
             Button(
@@ -62,7 +63,7 @@ fun PowerBlock(
                     .size(64.dp)
                     .clipCircle()
                     .circleBorder(2.dp, textColor.alpha(0.5f))
-                    .circleShadow(4.dp, Color.Black),
+                    .circleShadow(4.dp, shadowColor),
                 contentPadding = PaddingValues(1.dp),
                 onClick = onPowerButtonClick,
                 colors = ButtonDefaults.transparent(),
@@ -85,4 +86,6 @@ fun PowerBlock(
 
 @Preview
 @Composable
-fun PowerBlockPreview() = PowerBlock()
+fun PowerBlockPreview() = preview {
+    PowerBlock()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/custom/VerticalScrollableBox.kt

@@ -17,6 +17,7 @@ import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import eu.mjdev.desktop.extensions.Compose.isLandscapeMode
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.verticalTouchScrollable
 
 @Composable
@@ -36,4 +37,6 @@ fun VerticalScrollableBox(
 
 @Preview
 @Composable
-fun VerticalScrollableBoxPreview() = VerticalScrollableBox()
+fun VerticalScrollableBoxPreview() = preview {
+    VerticalScrollableBox()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/desktop/Desktop.kt

@@ -12,6 +12,7 @@ import eu.mjdev.desktop.components.desktop.widgets.MemoryChart
 import eu.mjdev.desktop.components.file.FolderView
 import eu.mjdev.desktop.components.sliding.base.VisibilityState
 import eu.mjdev.desktop.components.sliding.base.VisibilityState.Companion.rememberVisibilityState
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberCalculated
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
@@ -56,4 +57,6 @@ fun Desktop(
 
 @Preview
 @Composable
-fun DesktopPreview() = Desktop()
+fun DesktopPreview() = preview {
+    Desktop()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/desktop/widgets/MemoryChart.kt

@@ -10,6 +10,7 @@ import com.aay.compose.baseComponents.model.LegendPosition
 import com.aay.compose.donutChart.model.PieChartData
 import eu.mjdev.desktop.components.charts.DonutChart
 import eu.mjdev.desktop.components.draggable.DraggableView
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.helpers.system.MemInfo
 import eu.mjdev.desktop.helpers.system.MemInfo.Companion.toReadable
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
@@ -60,4 +61,6 @@ fun MemoryChart(
 
 @Preview
 @Composable
-fun MemoryChartPreview() = MemoryChart()
+fun MemoryChartPreview() = preview {
+    MemoryChart()
+}

+ 5 - 1
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanel.kt

@@ -38,6 +38,7 @@ import eu.mjdev.desktop.data.App
 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.preview
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.extensions.Modifier.topShadow
 import eu.mjdev.desktop.helpers.animation.Animations.DesktopPanelEnterAnimation
@@ -229,6 +230,9 @@ fun DesktopPanel(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun DesktopPanelPreview() = DesktopPanel()
+fun DesktopPanelPreview() = preview {
+    DesktopPanel()
+}

+ 6 - 1
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelIcon.kt

@@ -23,6 +23,7 @@ import eu.mjdev.desktop.extensions.Compose.onMouseEnter
 import eu.mjdev.desktop.extensions.Compose.onMouseLeave
 import eu.mjdev.desktop.extensions.Compose.onMousePress
 import eu.mjdev.desktop.extensions.Compose.onRightClick
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberCalculated
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
@@ -102,4 +103,8 @@ fun DesktopPanelIcon(
 
 @Preview
 @Composable
-fun DesktopPanelIconPreview() = DesktopPanelIcon()
+fun DesktopPanelIconPreview() = preview {
+    DesktopPanelIcon(
+        app = App.Test
+    )
+}

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

@@ -18,6 +18,7 @@ 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.preview
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
@@ -61,4 +62,6 @@ fun DesktopPanelText(
 
 @Preview
 @Composable
-fun DesktopPanelTextPreview() = DesktopPanelText()
+fun DesktopPanelTextPreview() = preview {
+    DesktopPanelText()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/DesktopPanelTray.kt

@@ -11,6 +11,7 @@ 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.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 // todo
@@ -31,4 +32,6 @@ fun DesktopPanelTray(
 
 @Preview
 @Composable
-fun DesktopPanelTrayPreview() = DesktopPanelTray()
+fun DesktopPanelTrayPreview() = preview {
+    DesktopPanelTray()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopMenuIcon.kt

@@ -9,6 +9,7 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.desktoppanel.DesktopPanelIcon
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Suppress("FunctionName")
 @Composable
@@ -42,4 +43,6 @@ fun DesktopMenuIcon(
 
 @Preview
 @Composable
-fun DesktopMenuIconPreview() = DesktopMenuIcon()
+fun DesktopMenuIconPreview() = preview {
+    DesktopMenuIcon()
+}

+ 5 - 1
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopPanelDateTime.kt

@@ -20,6 +20,7 @@ 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.preview
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
@@ -64,6 +65,9 @@ fun DesktopPanelDateTime(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun DesktopPanelDateTimePreview() = DesktopPanelDateTime()
+fun DesktopPanelDateTimePreview() = preview {
+    DesktopPanelDateTime()
+}

+ 5 - 2
src/main/kotlin/eu/mjdev/desktop/components/desktoppanel/applets/DesktopPanelFavoriteApps.kt

@@ -16,8 +16,8 @@ import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.desktoppanel.DesktopPanelIcon
 import eu.mjdev.desktop.data.App
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Custom.flowBlock
-import eu.mjdev.desktop.managers.processes.ProcessManager.Companion.rememberProcessManager
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 @Suppress("FunctionName")
@@ -67,6 +67,9 @@ fun DesktopPanelFavoriteApps(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun DesktopPanelFavoriteAppsPreview() = DesktopPanelFavoriteApps()
+fun DesktopPanelFavoriteAppsPreview() = preview {
+    DesktopPanelFavoriteApps()
+}

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

@@ -4,6 +4,7 @@ import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import eu.mjdev.desktop.components.desktoppanel.DesktopPanelText
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 @Suppress("FunctionName")
@@ -24,4 +25,6 @@ fun DesktopPanelLanguage(
 
 @Preview
 @Composable
-fun DesktopPanelLanguagePreview() = DesktopPanelLanguage()
+fun DesktopPanelLanguagePreview() = preview {
+    DesktopPanelLanguage()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/draggable/DraggableView.kt

@@ -15,6 +15,7 @@ import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.zIndex
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.extensions.Modifier.conditional
 
@@ -85,4 +86,6 @@ fun DraggableView(
 
 @Preview
 @Composable
-fun DraggableViewPreview() = DraggableView()
+fun DraggableViewPreview() = preview {
+    DraggableView()
+}

+ 15 - 4
src/main/kotlin/eu/mjdev/desktop/components/file/FolderIcon.kt

@@ -14,12 +14,14 @@ 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.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Custom.plus
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
+import eu.mjdev.desktop.extensions.Modifier.circleShadow
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import java.io.File
 
-@Suppress("FunctionName")
+@Suppress("FunctionName", "UNNECESSARY_SAFE_CALL")
 @Composable
 fun FolderIcon(
     path: File = File("/"),
@@ -32,7 +34,13 @@ fun FolderIcon(
     onContextMenuClick: () -> Unit = {},
     onClick: () -> Unit = {},
 ) = withDesktopScope {
-    val iconName = remember(path) { path.extension.ifEmpty { "folder" } } // todo mime type
+    val iconName = remember(path) {
+        when {
+            path.absolutePath?.contentEquals("/") == true -> "root"
+            path.absolutePath?.contentEquals("~") == true -> "home"
+            else -> path.extension.ifEmpty { "folder" }
+        }
+    } // todo from mime type
     val iconId: Int = remember(path) { iconSet.iconForName(iconName) ?: "?".toInt() }
     val computedSize = remember(path) { iconSize + 2.dp }
     DraggableView(
@@ -49,6 +57,7 @@ fun FolderIcon(
             Box(
                 modifier = Modifier.size(computedSize)
                     .circleBorder(2.dp, textColor)
+                    .circleShadow(4.dp)
             ) {
                 FontIcon(
                     iconId = iconId,
@@ -64,7 +73,7 @@ fun FolderIcon(
             TextWithShadow(
                 modifier = Modifier.width(computedSize.width)
                     .padding(start = 4.dp),
-                text = (customName ?: path.name).orEmpty(),
+                text = (customName ?: path.name).orEmpty().ifEmpty { iconName },
                 color = textColor,
                 fontWeight = FontWeight.Bold,
                 overflow = Ellipsis,
@@ -78,4 +87,6 @@ fun FolderIcon(
 
 @Preview
 @Composable
-fun FolderIconPreview() = FolderIcon()
+fun FolderIconPreview() = preview {
+    FolderIcon()
+}

+ 8 - 1
src/main/kotlin/eu/mjdev/desktop/components/file/FolderView.kt

@@ -2,6 +2,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.fillMaxSize
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.derivedStateOf
@@ -21,6 +22,7 @@ import eu.mjdev.desktop.components.sliding.base.VisibilityState
 import eu.mjdev.desktop.components.sliding.base.VisibilityState.Companion.rememberVisibilityState
 import eu.mjdev.desktop.data.DesktopFolderItem
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import java.io.File
 import kotlin.math.max
@@ -140,6 +142,11 @@ private fun rememberFiles(
     }
 }
 
+//todo
 @Preview
 @Composable
-fun FolderViewPreview() = FolderView()
+fun FolderViewPreview() = preview {
+    FolderView(
+        modifier = Modifier.fillMaxSize()
+    )
+}

+ 70 - 23
src/main/kotlin/eu/mjdev/desktop/components/fonticon/FontIcon.kt

@@ -3,6 +3,7 @@
 package eu.mjdev.desktop.components.fonticon
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.PaddingValues
 import androidx.compose.foundation.shape.CircleShape
 import androidx.compose.runtime.Composable
@@ -14,15 +15,16 @@ import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.icon.ShapedIcon
 import eu.mjdev.desktop.components.text.AutoResizeText
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.fonts.MaterialIconFont
-import eu.mjdev.desktop.provider.DesktopProvider.Companion.LocalDesktop
+import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 @Suppress("FunctionName")
 @Composable
 fun FontIcon(
     modifier: Modifier = Modifier,
     iconId: Int = 0,
-    iconicFont: MaterialIconFont = LocalDesktop.current.currentUser.theme.iconSet,
+    iconicFont: MaterialIconFont? = null,
     iconSize: DpSize = DpSize(32.dp, 32.dp),
     iconColor: Color = Color.Black,
     iconBackgroundColor: Color = Color.White,
@@ -32,27 +34,72 @@ fun FontIcon(
     iconShape: Shape = CircleShape,
     onRightClick: () -> Unit = {},
     onClick: () -> Unit = {}
-) = ShapedIcon(
-    modifier = modifier,
-    iconSize = iconSize,
-    iconColor = iconColor,
-    iconBackgroundColor = iconBackgroundColor,
-    contentDescription = contentDescription,
-    iconShape = iconShape,
-    innerPadding = innerPadding,
-    outerPadding = outerPadding,
-    customContent = {
-        AutoResizeText(
-            modifier = Modifier.align(Alignment.Center),
-            text = iconId.toChar().toString(),
-            color = iconColor,
-            fontFamily = iconicFont.fontFamily,
-        )
-    },
-    onClick = onClick,
-    onRightClick = onRightClick
-)
+) = withDesktopScope {
+    ShapedIcon(
+        modifier = modifier,
+        iconSize = iconSize,
+        iconColor = iconColor,
+        iconBackgroundColor = iconBackgroundColor,
+        contentDescription = contentDescription,
+        iconShape = iconShape,
+        innerPadding = innerPadding,
+        outerPadding = outerPadding,
+        customContent = {
+            AutoResizeText(
+                modifier = Modifier.align(Alignment.Center),
+                text = iconId.toChar().toString(),
+                color = iconColor,
+                fontFamily = (iconicFont ?: theme.iconSet).fontFamily,
+            )
+        },
+        onClick = onClick,
+        onRightClick = onRightClick
+    )
+}
+
+@Suppress("FunctionName")
+@Composable
+fun FontIcon(
+    modifier: Modifier = Modifier,
+    iconName: String = "",
+    iconicFont: MaterialIconFont? = null,
+    iconSize: DpSize = DpSize(32.dp, 32.dp),
+    iconColor: Color = Color.Black,
+    iconBackgroundColor: Color = Color.White,
+    innerPadding: PaddingValues = PaddingValues(4.dp),
+    contentDescription: String = "",
+    outerPadding: PaddingValues = PaddingValues(2.dp),
+    iconShape: Shape = CircleShape,
+    onRightClick: () -> Unit = {},
+    onClick: () -> Unit = {}
+) = withDesktopScope {
+    ShapedIcon(
+        modifier = modifier,
+        iconSize = iconSize,
+        iconColor = iconColor,
+        iconBackgroundColor = iconBackgroundColor,
+        contentDescription = contentDescription,
+        iconShape = iconShape,
+        innerPadding = innerPadding,
+        outerPadding = outerPadding,
+        customContent = {
+            AutoResizeText(
+                modifier = Modifier.align(Alignment.Center),
+                text = (iconSet.iconForName(iconName) ?: "?".toInt()).toChar().toString(),
+                color = iconColor,
+                fontFamily = (iconicFont ?: theme.iconSet).fontFamily,
+            )
+        },
+        onClick = onClick,
+        onRightClick = onRightClick
+    )
+}
 
 @Preview
 @Composable
-fun FontIconPreview() = FontIcon()
+fun FontIconPreview() = preview {
+    Column {
+        FontIcon(iconId = 0)
+        FontIcon(iconName = "")
+    }
+}

+ 19 - 14
src/main/kotlin/eu/mjdev/desktop/components/gallery/BoxWithControls.kt

@@ -1,6 +1,7 @@
 package eu.mjdev.desktop.components.gallery
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.gestures.detectTapGestures
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
@@ -9,8 +10,10 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.pointer.pointerInput
 import eu.mjdev.desktop.components.image.ImageColoredBackground
 import eu.mjdev.desktop.extensions.Compose.onKey
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Custom.toggle
 
 @Composable
@@ -30,19 +33,19 @@ fun BoxWithControls(
         controlsState: MutableState<Boolean>
     ) -> Unit = { _, _, _ -> }
 ) = ImageColoredBackground(
-    modifier = modifier
-//        .swipeGestures(
-//            onTap = {  controlsState.toggle() }
-//        )
-        .onKey(Key.Enter) {
-            controlsState.toggle()
-        }
-        .onKey(Key.DirectionDown) {
-            controlsState.value = false
-        }
-        .onKey(Key.DirectionUp) {
-            controlsState.value = true
-        },
+    modifier = modifier.pointerInput(Unit) {
+        detectTapGestures(
+            onTap = {
+                controlsState.toggle()
+            }
+        )
+    }.onKey(Key.Enter) {
+        controlsState.toggle()
+    }.onKey(Key.DirectionDown) {
+        controlsState.value = false
+    }.onKey(Key.DirectionUp) {
+        controlsState.value = true
+    },
     src = src,
     contentAlignment = contentAlignment,
 ) { bckColor ->
@@ -54,4 +57,6 @@ fun BoxWithControls(
 
 @Preview
 @Composable
-fun BoxWithControlsPreview() = BoxWithControls()
+fun BoxWithControlsPreview() = preview {
+    BoxWithControls()
+}

+ 21 - 14
src/main/kotlin/eu/mjdev/desktop/components/gallery/Gallery.kt

@@ -21,16 +21,19 @@ import eu.mjdev.desktop.components.card.PhotoCard
 import eu.mjdev.desktop.components.image.ImageAny
 import eu.mjdev.desktop.components.immersivelist.ImmersiveList
 import eu.mjdev.desktop.components.immersivelist.base.ImmersiveInnerList
+import eu.mjdev.desktop.data.App
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberDerivedState
 import eu.mjdev.desktop.extensions.Compose.rememberFocusRequester
 import eu.mjdev.desktop.helpers.bitmap.Bitmap
 import kotlinx.coroutines.delay
 import java.io.File
 
+// todo
 @Composable
 fun Gallery(
     modifier: Modifier = Modifier,
-    list: List<Any?> = listOf(Unit),
+    list: List<Any?> = listOf(),
     index: Int = 0,
     delayedHide: Long = 5000,
     controlsState: MutableState<Boolean> = remember { mutableStateOf(true) },
@@ -56,18 +59,18 @@ fun Gallery(
     ) -> Unit = { _, _, _ -> },
 ) {
     val initialized = remember(list, index) { mutableStateOf(false) }
-//    val nextItem: () -> Unit = {
-//        if (currentItemIndex.intValue < (list.size - 1)) {
-//            currentItemIndex.intValue += 1
-//        }
-//        controlsState.value = true
-//    }
-//    val prevItem: () -> Unit = {
-//        if (currentItemIndex.intValue > 0) {
-//            currentItemIndex.intValue -= 1
-//        }
-//        controlsState.value = true
-//    }
+    val nextItem: () -> Unit = {
+        if (currentItemIndex.intValue < (list.size - 1)) {
+            currentItemIndex.intValue += 1
+        }
+        controlsState.value = true
+    }
+    val prevItem: () -> Unit = {
+        if (currentItemIndex.intValue > 0) {
+            currentItemIndex.intValue -= 1
+        }
+        controlsState.value = true
+    }
     val itemState = rememberDerivedState(0, currentItemIndex.intValue) {
         list[currentItemIndex.intValue]
     }
@@ -196,4 +199,8 @@ val contentScaleSaver = Saver<MutableState<ContentScale>, String>(
 
 @Preview
 @Composable
-fun GalleryPreview() = Gallery()
+fun GalleryPreview() = preview {
+    Gallery(
+        list = listOf(App.Test, App.Test, App.Test),
+    )
+}

+ 8 - 4
src/main/kotlin/eu/mjdev/desktop/components/gallery/ItemInfo.kt

@@ -16,12 +16,14 @@ import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import eu.mjdev.desktop.components.text.AutoHideEmptyText
+import eu.mjdev.desktop.data.ItemWithDate
+import eu.mjdev.desktop.data.ItemWithTitle
 import eu.mjdev.desktop.extensions.ColorUtils.createVerticalColorBrush
 import eu.mjdev.desktop.extensions.ColorUtils.invert
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.helpers.compose.Gravity
 
 // todo
-@Suppress("UNUSED_PARAMETER")
 @Composable
 fun ItemInfo(
     modifier: Modifier = Modifier,
@@ -30,10 +32,10 @@ fun ItemInfo(
     backgroundColor: Color = Color.Transparent,
 //    metadataRetriever: MetadataRetriever = rememberMetaDataRetriever(),
     titleFromItem: () -> Any? = {
-//        (src as? ItemWithTitle<*>)?.title
+        (src as? ItemWithTitle)?.title
     },
     dateFromItem: () -> Any? = {
-//        (src as? ItemWithDate)?.date ?: "-"
+        (src as? ItemWithDate)?.date?.toString() ?: "-"
     },
     detailsFromItem: () -> Any? = {
 //        metadataRetriever.getInfo(src)
@@ -83,4 +85,6 @@ fun ItemInfo(
 
 @Preview
 @Composable
-fun ItemInfoPreview() = ItemInfo()
+fun ItemInfoPreview() = preview {
+    ItemInfo()
+}

+ 10 - 2
src/main/kotlin/eu/mjdev/desktop/components/greeter/Greeter.kt

@@ -12,14 +12,17 @@ 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.style.TextAlign
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.WindowPosition
 import eu.mjdev.desktop.components.input.PasswordTextView
 import eu.mjdev.desktop.components.user.UserAvatar
 import eu.mjdev.desktop.data.User
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberState
 import eu.mjdev.desktop.extensions.Compose.runAsync
+import eu.mjdev.desktop.helpers.compose.Orientation
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import eu.mjdev.desktop.windows.ChromeWindow
 import kotlinx.coroutines.flow.collectLatest
@@ -30,7 +33,7 @@ import kotlinx.coroutines.flow.collectLatest
 fun Greeter() = withDesktopScope {
     val user: User by rememberState(api.currentUser)
     var isUserLoggedIn by rememberState(user.isLoggedIn)
-    var passwordVisible by rememberState(false)
+    var passwordVisible by rememberState(isDebug)
     val onDone: (password: String) -> Unit = { password ->
         runAsync {
             user.login(api, password).collectLatest { logState ->
@@ -58,6 +61,9 @@ fun Greeter() = withDesktopScope {
                 UserAvatar(
                     modifier = Modifier,
                     avatarSize = 128.dp,
+                    orientation = Orientation.Vertical,
+                    textAlign = TextAlign.Center,
+                    cicleBorder = 4.dp,
                     onUserAvatarClick = {
                         passwordVisible = true
                     }
@@ -82,4 +88,6 @@ fun Greeter() = withDesktopScope {
 
 @Preview
 @Composable
-fun GreeterPreview() = Greeter()
+fun GreeterPreview() = preview {
+    Greeter()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/grid/GridPlaced.kt

@@ -8,6 +8,7 @@ import androidx.compose.ui.unit.Constraints
 import eu.mjdev.desktop.components.grid.base.*
 import eu.mjdev.desktop.components.grid.base.Measure.calculateCellPlaces
 import eu.mjdev.desktop.components.grid.base.Measure.measure
+import eu.mjdev.desktop.extensions.Compose.preview
 import kotlin.math.min
 
 @Composable
@@ -51,4 +52,6 @@ fun GridPlaced(
 
 @Preview
 @Composable
-fun GridPlacedPreview() = GridPlaced()
+fun GridPlacedPreview() = preview {
+    GridPlaced()
+}

+ 8 - 1
src/main/kotlin/eu/mjdev/desktop/components/guide/GuideView.kt

@@ -19,6 +19,7 @@ import androidx.compose.ui.graphics.StrokeCap
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.extensions.Compose.preview
 import kotlin.math.max
 
 @Composable
@@ -57,4 +58,10 @@ fun GuideLines(
 
 @Preview
 @Composable
-fun GuideLinesPreview() = GuideLines(modifier = Modifier.fillMaxSize())
+fun GuideLinesPreview() = preview(320, 320) {
+    GuideLines(
+        modifier = Modifier.fillMaxSize(),
+        cellSize = DpSize(32.dp, 32.dp),
+        color = Color.White
+    )
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/icon/ShapedIcon.kt

@@ -18,6 +18,7 @@ import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.extensions.Compose.onLeftClick
 import eu.mjdev.desktop.extensions.Compose.onMousePress
 import eu.mjdev.desktop.extensions.Compose.onRightClick
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.size
 
 @Composable
@@ -70,4 +71,6 @@ fun ShapedIcon(
 
 @Preview
 @Composable
-fun ShapedIconPreview() = ShapedIcon()
+fun ShapedIconPreview() = preview {
+    ShapedIcon()
+}

+ 13 - 7
src/main/kotlin/eu/mjdev/desktop/components/icon/WifiLevelIcon.kt

@@ -14,10 +14,10 @@ import androidx.compose.runtime.Composable
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
 import androidx.compose.ui.unit.DpSize
 import androidx.compose.ui.unit.dp
-import eu.mjdev.desktop.components.image.ImageAny
+import com.composables.core.Icon
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.rememberComputed
 import eu.mjdev.desktop.icons.Icons
 import eu.mjdev.desktop.icons.wifi.level.*
@@ -25,7 +25,7 @@ import eu.mjdev.desktop.icons.wifi.level.*
 @Composable
 fun WifiLevelIcon(
     modifier: Modifier = Modifier,
-    level: Int = 55,
+    level: Int,
     color: Color = Color.Black,
     iconSize: DpSize = DpSize(24.dp, 24.dp)
 ) {
@@ -39,13 +39,19 @@ fun WifiLevelIcon(
             else -> Icons.Wifi_Level_0
         }
     }
-    ImageAny(
+    Icon(
         modifier = modifier.size(iconSize),
-        src = levelIcon,
-        colorFilter = ColorFilter.tint(color)
+        imageVector = levelIcon,
+        contentDescription = "",
+        tint = color
     )
 }
 
 @Preview
 @Composable
-fun WifiLevelIconPreview() = WifiLevelIcon()
+fun WifiLevelIconPreview() = preview {
+    WifiLevelIcon(
+        level = 55,
+        color = Color.White
+    )
+}

+ 5 - 1
src/main/kotlin/eu/mjdev/desktop/components/image/GifView.kt

@@ -7,6 +7,7 @@ import androidx.compose.runtime.*
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.toComposeImageBitmap
 import androidx.compose.ui.unit.IntSize
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.helpers.gif.GifDecoder
 import kotlinx.coroutines.delay
 import java.awt.image.BufferedImage
@@ -47,6 +48,9 @@ fun GifView(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun GifViewPreview() = GifView()
+fun GifViewPreview() = preview {
+    GifView()
+}

+ 14 - 5
src/main/kotlin/eu/mjdev/desktop/components/image/ImageAny.kt

@@ -4,7 +4,7 @@ import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Box
 import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.SupervisedUserCircle
+import androidx.compose.material.icons.filled.BrokenImage
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
@@ -16,6 +16,7 @@ import androidx.compose.ui.layout.ContentScale
 import coil3.compose.AsyncImage
 import eu.mjdev.desktop.components.video.VideoView
 import eu.mjdev.desktop.extensions.Compose.asyncImageLoader
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Custom.flowBlock
 import eu.mjdev.desktop.helpers.internal.ImagesProvider
 import eu.mjdev.desktop.helpers.internal.ImagesProvider.Companion.getOne
@@ -27,7 +28,7 @@ import androidx.compose.foundation.Image as ComposeImage
 @Suppress("FunctionName", "UNUSED_PARAMETER")
 @Composable
 fun ImageAny(
-    src: Any? = Icons.Filled.SupervisedUserCircle,
+    src: Any? = null,
     contentDescription: String? = "",
     modifier: Modifier = Modifier,
     alignment: Alignment = Alignment.Center,
@@ -49,8 +50,14 @@ fun ImageAny(
         it.endsWith(".mp4") || it.endsWith(".mpg")
     }
     when {
-        image.value == null -> Box(
-            modifier = modifier
+        image.value == null -> ComposeImage(
+            modifier = modifier,
+            imageVector = Icons.Default.BrokenImage,
+            alignment = alignment,
+            alpha = alpha,
+            contentDescription = contentDescription,
+            colorFilter = colorFilter,
+            contentScale = contentScale
         )
 
         image.value is Color -> Box(
@@ -137,4 +144,6 @@ fun ImageAny(
 
 @Preview
 @Composable
-fun ImageAnyPreview() = ImageAny()
+fun ImageAnyPreview() = preview {
+    ImageAny()
+}

+ 5 - 1
src/main/kotlin/eu/mjdev/desktop/components/image/ImageColoredBackground.kt

@@ -22,6 +22,7 @@ import eu.mjdev.desktop.extensions.BitmapUtils.cut
 import eu.mjdev.desktop.extensions.BitmapUtils.topMostColor
 import eu.mjdev.desktop.extensions.ColorUtils.nonAlphaValue
 import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Image.loadPicture
 import eu.mjdev.desktop.extensions.Modifier.conditional
 
@@ -74,6 +75,9 @@ fun ImageColoredBackground(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun ImageColoredBackgroundPreview() = ImageColoredBackground()
+fun ImageColoredBackgroundPreview() = preview {
+    ImageColoredBackground()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/image/PhotoImage.kt

@@ -26,6 +26,7 @@ import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.layout.ContentScale
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.extensions.Compose.preview
 
 // todo
 @Composable
@@ -127,4 +128,6 @@ fun PhotoImage(
 
 @Preview
 @Composable
-fun PhotoImagePreview() = PhotoImage()
+fun PhotoImagePreview() = preview {
+    PhotoImage()
+}

+ 5 - 1
src/main/kotlin/eu/mjdev/desktop/components/immersivelist/ImmersiveList.kt

@@ -12,6 +12,7 @@ import androidx.compose.ui.platform.LocalFocusManager
 import eu.mjdev.desktop.components.immersivelist.base.ImmersiveListBackgroundScope
 import eu.mjdev.desktop.components.immersivelist.base.ImmersiveListScope
 import eu.mjdev.desktop.extensions.Compose.bringIntoViewIfChildrenAreFocused
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Suppress("IllegalExperimentalApiUsage")
 @OptIn(ExperimentalComposeUiApi::class)
@@ -50,6 +51,9 @@ fun ImmersiveList(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun ImmersiveListPreview() = ImmersiveList()
+fun ImmersiveListPreview() = preview {
+    ImmersiveList()
+}

+ 8 - 6
src/main/kotlin/eu/mjdev/desktop/components/info/InfoWindow.kt

@@ -11,13 +11,13 @@ 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.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.components.text.AutoResizeText
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import eu.mjdev.desktop.windows.ChromeWindow
 
@@ -45,12 +45,12 @@ fun InfoWindow(
                 BackgroundImage(
                     modifier = Modifier.fillMaxSize()
                 )
-                TextAny(
-                    modifier = Modifier.padding(bottom = 128.dp, start = 16.dp),
+                AutoResizeText(
+                    modifier = Modifier.padding(bottom = 128.dp, start = 16.dp)
+                        .height(32.dp),
                     text = "Welcome to mjdev desktop",
                     fontStyle = FontStyle.Italic,
                     fontWeight = FontWeight.Bold,
-                    fontSize = 48.sp
                 )
                 Box(
                     modifier = Modifier.fillMaxWidth()
@@ -78,4 +78,6 @@ fun InfoWindow(
 
 @Preview
 @Composable
-fun InfoWindowPreview() = InfoWindow()
+fun InfoWindowPreview() = preview {
+    InfoWindow()
+}

+ 13 - 2
src/main/kotlin/eu/mjdev/desktop/components/input/PasswordTextView.kt

@@ -16,14 +16,17 @@ import androidx.compose.runtime.*
 import androidx.compose.runtime.saveable.rememberSaveable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.text.input.KeyboardType
 import androidx.compose.ui.text.input.PasswordVisualTransformation
 import androidx.compose.ui.text.input.VisualTransformation
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.icons.Icons
 
+// todo check colors
 @Suppress("FunctionName")
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
@@ -31,6 +34,8 @@ fun PasswordTextView(
     modifier: Modifier = Modifier,
     password: MutableState<String> = rememberSaveable { mutableStateOf("") },
     passwordVisible: MutableState<Boolean> = rememberSaveable { mutableStateOf(false) },
+    backgroundColor: Color = Color.White.copy(0.5f),
+    textColor: Color = Color.Black,
     label: @Composable (() -> Unit)? = null,
     placeholder: @Composable () -> Unit = {},
     shape: Shape = RoundedCornerShape(8.dp),
@@ -66,7 +71,9 @@ fun PasswordTextView(
         label = label,
         singleLine = true,
         shape = shape,
-        colors = colors,
+        colors = TextFieldDefaults.textFieldColors(
+            backgroundColor = backgroundColor,
+        ),
         placeholder = placeholder,
         visualTransformation = if (passwordVisible.value) VisualTransformation.None else PasswordVisualTransformation(),
         keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
@@ -95,4 +102,8 @@ fun PasswordTextView(
 
 @Preview
 @Composable
-fun PasswordTextViewPreview() = PasswordTextView()
+fun PasswordTextViewPreview() = preview {
+    PasswordTextView(
+        password = mutableStateOf("test")
+    )
+}

+ 9 - 2
src/main/kotlin/eu/mjdev/desktop/components/input/SearchFieldPassive.kt

@@ -25,6 +25,8 @@ import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.icons.Icons
 
 @OptIn(ExperimentalFoundationApi::class)
@@ -33,6 +35,7 @@ fun SearchFieldPassive(
     modifier: Modifier = Modifier,
     textState: MutableState<String> = mutableStateOf(""),
     textColor: Color = Color.White,
+    backgroundColor: Color = Color.White.alpha(0.2f),
     textStyle: TextStyle = TextStyle.Default,
     textSize: TextUnit = 18.sp,
     onClearClick: () -> Unit = {}
@@ -44,7 +47,7 @@ fun SearchFieldPassive(
     textStyle = textStyle,
     textSize = textSize,
     colors = TextFieldDefaults.outlinedTextFieldColors(
-        backgroundColor = Color.Transparent,
+        backgroundColor = backgroundColor,
         textColor = textColor,
         disabledTextColor = textColor,
         cursorColor = Color.Transparent,
@@ -70,4 +73,8 @@ fun SearchFieldPassive(
 
 @Preview
 @Composable
-fun SearchFieldPassivePreview() = SearchFieldPassive()
+fun SearchFieldPassivePreview() = preview {
+    SearchFieldPassive(
+        textState = mutableStateOf("test")
+    )
+}

+ 6 - 1
src/main/kotlin/eu/mjdev/desktop/components/input/SelectableOutlineEditText.kt

@@ -15,6 +15,7 @@ import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.input.TextFieldValue
 import androidx.compose.ui.text.input.VisualTransformation
 import androidx.compose.ui.unit.TextUnit
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Composable
 fun SelectableOutlineEditText(
@@ -110,4 +111,8 @@ fun SelectableOutlineEditText(
 
 @Preview
 @Composable
-fun SelectableOutlineEditTextPreview() = SelectableOutlineEditText()
+fun SelectableOutlineEditTextPreview() = preview {
+    SelectableOutlineEditText(
+        value = "test"
+    )
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/installer/Installer.kt

@@ -16,6 +16,7 @@ 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.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import eu.mjdev.desktop.windows.ChromeWindow
 
@@ -57,4 +58,6 @@ fun Installer(
 
 @Preview
 @Composable
-fun InfoWindowPreview() = Installer()
+fun InfoWindowPreview() = preview {
+    Installer()
+}

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

@@ -13,6 +13,7 @@ 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.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import eu.mjdev.desktop.windows.ChromeWindowState.Companion.rememberChromeWindowState
 import eu.mjdev.desktop.windows.DesktopWindow
@@ -76,6 +77,9 @@ fun MainWindow() = withDesktopScope {
     }
 }
 
+// todo
 @Preview
 @Composable
-fun MainWindowPreview() = MainWindow()
+fun MainWindowPreview() = preview {
+    MainWindow()
+}

+ 7 - 2
src/main/kotlin/eu/mjdev/desktop/components/menu/ContextMenu.kt

@@ -6,13 +6,15 @@ import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.CursorDropdownMenu
 import androidx.compose.material.DropdownMenuItem
 import androidx.compose.material.Text
-import androidx.compose.runtime.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.key
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.menu.base.ContextMenuState
 import eu.mjdev.desktop.components.menu.base.ContextMenuState.Companion.rememberContextMenuState
 import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
+import eu.mjdev.desktop.extensions.Compose.preview
 
 // todo
 @Suppress("unused", "FunctionName")
@@ -58,6 +60,9 @@ fun ContextMenu(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun ContextMenuPreview() = ContextMenu()
+fun ContextMenuPreview() = preview {
+    ContextMenu()
+}

+ 7 - 1
src/main/kotlin/eu/mjdev/desktop/components/progress/DashedProgressIndicator.kt

@@ -10,12 +10,14 @@ package eu.mjdev.desktop.components.progress
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.StrokeCap
 import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Composable
 fun DashedProgressIndicator(
@@ -48,4 +50,8 @@ fun DashedProgressIndicator(
 
 @Preview
 @Composable
-fun DashedProgressIndicatorPreview() = DashedProgressIndicator()
+fun DashedProgressIndicatorPreview() = preview {
+    DashedProgressIndicator(
+        modifier = Modifier.fillMaxWidth()
+    )
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/qrcode/QrCodeView.kt

@@ -11,6 +11,7 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.painter.Painter
 import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.extensions.Compose.preview
 import io.github.alexzhirkevich.qrose.options.*
 import io.github.alexzhirkevich.qrose.rememberQrCodePainter
 
@@ -58,4 +59,6 @@ fun QrCodeView(
 
 @Preview
 @Composable
-fun QrCodeViewPreview() = QrCodeView()
+fun QrCodeViewPreview() = preview(320, 320) {
+    QrCodeView()
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/sliding/SlidingPanel.kt

@@ -14,6 +14,7 @@ import eu.mjdev.desktop.components.sliding.base.VisibilityState
 import eu.mjdev.desktop.components.sliding.base.VisibilityState.Companion.rememberVisibilityState
 import eu.mjdev.desktop.extensions.Compose.onMouseEnter
 import eu.mjdev.desktop.extensions.Compose.onMouseLeave
+import eu.mjdev.desktop.extensions.Compose.preview
 
 // todo remove, move to chrome window
 @Suppress("FunctionName")
@@ -53,4 +54,6 @@ fun SlidingPanel(
 
 @Preview
 @Composable
-fun SlidingMenuPreview() = SlidingPanel()
+fun SlidingMenuPreview() = preview {
+    SlidingPanel()
+}

+ 9 - 1
src/main/kotlin/eu/mjdev/desktop/components/surface/Surface.kt

@@ -18,6 +18,10 @@ import androidx.compose.foundation.interaction.*
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.BoxScope
 import androidx.compose.material.LocalContentColor
+//import androidx.compose.material3.LocalAbsoluteTonalElevation
+//import androidx.compose.material3.LocalContentColor
+//import androidx.compose.material3.MaterialTheme
+//import androidx.compose.material3.surfaceColorAtElevation
 import androidx.compose.runtime.*
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
@@ -29,6 +33,7 @@ import androidx.compose.ui.unit.dp
 import eu.mjdev.desktop.components.surface.base.*
 import eu.mjdev.desktop.extensions.Compose.onMouseLongPress
 import eu.mjdev.desktop.extensions.Compose.onMousePress
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Modifier.conditional
 import eu.mjdev.desktop.helpers.compose.surfaceBorder
 import eu.mjdev.desktop.helpers.compose.zIndex
@@ -208,6 +213,9 @@ internal const val EnabledContentAlpha = 1f
 private const val FocusedZIndex = 0.5f
 private const val NonFocusedZIndex = 0f
 
+// todo
 @Preview
 @Composable
-fun SurfacePreview() = Surface()
+fun SurfacePreview() = preview {
+    Surface()
+}

+ 4 - 5
src/main/kotlin/eu/mjdev/desktop/components/surface/base/ClickableSurfaceGlow.kt

@@ -11,11 +11,10 @@ package eu.mjdev.desktop.components.surface.base
 import androidx.compose.runtime.Immutable
 
 @Immutable
-class ClickableSurfaceGlow
-internal constructor(
-    internal val glow: Glow,
-    internal val focusedGlow: Glow,
-    internal val pressedGlow: Glow
+class ClickableSurfaceGlow(
+    val glow: Glow,
+    val focusedGlow: Glow,
+    val pressedGlow: Glow
 ) {
     override fun equals(other: Any?): Boolean {
         if (this === other) return true

+ 2 - 1
src/main/kotlin/eu/mjdev/desktop/components/surface/base/SurfaceGlow.kt

@@ -177,7 +177,8 @@ private class SurfaceGlowNode(
         )
     }
 
+    // todo
     fun Paint.setShadowLayer(radius: Float, dx: Float, dy: Float, shadowColor: Color) {
-        setShadowLayer(radius, dx, dy, shadowColor)
+//        this.setShadowLayer(radius, dx, dy, shadowColor)
     }
 }

+ 18 - 3
src/main/kotlin/eu/mjdev/desktop/components/text/AutoHideEmptyText.kt

@@ -1,6 +1,7 @@
 package eu.mjdev.desktop.components.text
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
 import androidx.compose.material.LocalTextStyle
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
@@ -14,6 +15,7 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.TextUnit
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.textFrom
 
 @Composable
@@ -36,8 +38,7 @@ fun AutoHideEmptyText(
     minLines: Int = 1,
     onTextLayout: (TextLayoutResult) -> Unit = {},
     style: TextStyle = LocalTextStyle.current
-) {
-    val textAny = textFrom(text)
+) = textFrom(text).also { textAny ->
     if (textAny.isNotEmpty()) {
         TextAny(
             text = text,
@@ -63,4 +64,18 @@ fun AutoHideEmptyText(
 
 @Preview
 @Composable
-fun AutoHideEmptyTextPreview() = AutoHideEmptyText()
+fun AutoHideEmptyTextPreview() = preview {
+    AutoHideEmptyText(
+        modifier = Modifier.background(Color.White),
+        text = "test"
+    )
+}
+
+@Preview
+@Composable
+fun AutoHideEmptyTextEmptyPreview() = preview {
+    AutoHideEmptyText(
+        modifier = Modifier.background(Color.White),
+        text = ""
+    )
+}

+ 10 - 2
src/main/kotlin/eu/mjdev/desktop/components/text/AutoResizeText.kt

@@ -1,9 +1,11 @@
 package eu.mjdev.desktop.components.text
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.BoxWithConstraints
+import androidx.compose.foundation.layout.height
 import androidx.compose.material.Text
-import androidx.compose.runtime.*
+import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.text.font.FontFamily
@@ -13,6 +15,7 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
+import eu.mjdev.desktop.extensions.Compose.preview
 import kotlin.math.min
 
 // todo may be need refactor
@@ -41,4 +44,9 @@ fun AutoResizeText(
 
 @Preview
 @Composable
-fun AutoResizeTextPreview() = AutoResizeText()
+fun AutoResizeTextPreview() = preview {
+    AutoResizeText(
+        modifier = Modifier.height(48.dp).background(Color.White),
+        text = "test"
+    )
+}

+ 4 - 1
src/main/kotlin/eu/mjdev/desktop/components/text/CircleText.kt

@@ -19,6 +19,7 @@ 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.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Modifier.clipCircle
 
 @Suppress("unused", "FunctionName")
@@ -59,4 +60,6 @@ fun CircleText(
 
 @Preview
 @Composable
-fun CircleTextPreview() = CircleText()
+fun CircleTextPreview() = preview {
+    CircleText()
+}

+ 11 - 1
src/main/kotlin/eu/mjdev/desktop/components/text/TextAny.kt

@@ -1,6 +1,8 @@
 package eu.mjdev.desktop.components.text
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.text.selection.SelectionContainer
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
@@ -15,6 +17,9 @@ import androidx.compose.ui.text.style.TextAlign
 import androidx.compose.ui.text.style.TextDecoration
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.dp
+import eu.mjdev.desktop.data.App
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Compose.textFrom
 
 // todo weight does not work when selectable enabled
@@ -75,4 +80,9 @@ fun TextAny(
 
 @Preview
 @Composable
-fun TextAnyPreview() = TextAny()
+fun TextAnyPreview() = preview {
+    TextAny(
+        modifier = Modifier.height(48.dp).background(Color.White),
+        text = App.Test
+    )
+}

+ 10 - 1
src/main/kotlin/eu/mjdev/desktop/components/text/TextWithShadow.kt

@@ -1,6 +1,8 @@
 package eu.mjdev.desktop.components.text
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.height
 import androidx.compose.material.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
@@ -15,6 +17,8 @@ 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.data.App
+import eu.mjdev.desktop.extensions.Compose.preview
 
 @Suppress("FunctionName")
 @Composable
@@ -54,4 +58,9 @@ fun TextWithShadow(
 
 @Preview
 @Composable
-fun TextWithShadowPreview() = TextWithShadow()
+fun TextWithShadowPreview() = preview {
+    TextWithShadow(
+        modifier = Modifier.height(48.dp).background(Color.White),
+        text = App.Test
+    )
+}

+ 8 - 1
src/main/kotlin/eu/mjdev/desktop/components/tooltip/Tooltip.kt

@@ -22,6 +22,7 @@ import eu.mjdev.desktop.components.text.TextAny
 import eu.mjdev.desktop.data.App
 import eu.mjdev.desktop.data.TooltipData
 import eu.mjdev.desktop.extensions.Compose.launchedEffect
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import kotlinx.coroutines.delay
 
@@ -101,4 +102,10 @@ fun rememberTooltipState() = remember { TooltipState() }
 
 @Preview
 @Composable
-fun TooltipPreview() = Tooltip()
+fun TooltipPreview() = preview {
+    Tooltip(
+        tooltipState = rememberTooltipState().apply {
+            value = "test tooltip"
+        }
+    )
+}

+ 63 - 32
src/main/kotlin/eu/mjdev/desktop/components/user/UserAvatar.kt

@@ -29,10 +29,14 @@ import eu.mjdev.desktop.components.image.ImageAny
 import eu.mjdev.desktop.components.text.TextAny
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
 import eu.mjdev.desktop.extensions.Compose.SuperDarkGray
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.extensions.Modifier.circleBorder
 import eu.mjdev.desktop.extensions.Modifier.clipCircle
+import eu.mjdev.desktop.extensions.Modifier.conditional
+import eu.mjdev.desktop.helpers.compose.Orientation
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
+// todo move back orientation for greeter
 @Suppress("FunctionName")
 @Composable
 fun UserAvatar(
@@ -40,36 +44,46 @@ fun UserAvatar(
     avatarSize: Dp = 64.dp,
     titleTextSize: TextUnit = 16.sp,
     detailTextSize: TextUnit = 14.sp,
+    cicleBorder: Dp = 4.dp,
     iconVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
     titleVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
     actionsVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
-    titleHorizontalAlignment: Alignment.Horizontal = Alignment.Start,
     iconPadding: PaddingValues = PaddingValues(),
     titlePadding: PaddingValues = PaddingValues(),
     actionsPadding: PaddingValues = PaddingValues(),
+    orientation: Orientation = Orientation.Horizontal,
+    textAlign: TextAlign = TextAlign.Start,
     onUserAvatarClick: () -> Unit = {},
-    actions: @Composable RowScope.() -> Unit = {},
+    actions: @Composable() (RowScope.() -> Unit) = {},
 ) = withDesktopScope {
     val content: @Composable () -> Unit = {
         AppBar(
             iconVerticalAlignment = iconVerticalAlignment,
             titleVerticalAlignment = titleVerticalAlignment,
             actionsVerticalAlignment = actionsVerticalAlignment,
+            titleHorizontalArrangement = if (orientation == Orientation.Horizontal) Arrangement.Start
+            else Arrangement.Center,
+            iconHorizontalArrangement = if (orientation == Orientation.Horizontal) Arrangement.Start
+            else Arrangement.Center,
+            actionsHorizontalArrangement = if (orientation == Orientation.Horizontal) Arrangement.Start
+            else Arrangement.Center,
+            orientation = orientation,
             contentAlignment = Alignment.Bottom,
             iconPadding = iconPadding,
             titlePadding = titlePadding,
             actionsPadding = actionsPadding,
+            fillCenter = orientation == Orientation.Horizontal,
             icon = {
                 TransparentButton(
                     modifier = Modifier
-                        .size(avatarSize)
+                        .size(avatarSize + cicleBorder)
                         .clipCircle(),
                     onClick = onUserAvatarClick,
                 ) {
                     ImageAny(
                         modifier = Modifier
                             .size(avatarSize)
-                            .circleBorder(2.dp, textColor.alpha(0.5f)),
+                            .circleBorder(cicleBorder, textColor.alpha(0.5f)),
                         src = api.currentUser.picture,
                         colorFilter = if (api.currentUser.picture is ImageVector) ColorFilter.tint(iconsTintColor)
                         else null,
@@ -80,22 +94,28 @@ fun UserAvatar(
             title = {
                 Column(
                     modifier = Modifier.padding(start = 8.dp)
-                        .fillMaxWidth()
+                        .conditional(orientation == Orientation.Horizontal) {
+                            fillMaxWidth()
+                        }
+                        .conditional(orientation == Orientation.Vertical) {
+                            wrapContentSize()
+                        }
                         .padding(top = 8.dp),
                     verticalArrangement = Arrangement.Center,
-                    horizontalAlignment = titleHorizontalAlignment
                 ) {
                     TextAny(
+                        modifier = Modifier.fillMaxWidth(),
                         text = api.currentUser.userName,
                         color = textColor,
-                        textAlign = TextAlign.Start,
+                        textAlign = textAlign,
                         fontWeight = FontWeight.Bold,
                         fontSize = titleTextSize
                     )
                     TextAny(
+                        modifier = Modifier.fillMaxWidth(),
                         text = api.machineName,
                         color = textColor,
-                        textAlign = TextAlign.Start,
+                        textAlign = textAlign,
                         fontWeight = FontWeight.Medium,
                         fontSize = detailTextSize
                     )
@@ -109,34 +129,45 @@ fun UserAvatar(
             .wrapContentWidth()
             .padding(16.dp)
     ) {
-//        when (orientation) {
-//            Orientation.Vertical -> Column(
-//                modifier = Modifier
-//                    .fillMaxWidth()
-//                    .align(Alignment.Center),
-//                horizontalAlignment = Alignment.CenterHorizontally,
-//                content = { content(orientation) }
-//            )
+        when (orientation) {
+            Orientation.Vertical -> Column(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .align(Alignment.Center),
+                horizontalAlignment = Alignment.CenterHorizontally,
+                content = { content() }
+            )
 
-//            Orientation.Horizontal ->
-        Row(
-            modifier = Modifier
-                .fillMaxWidth()
-                .align(Alignment.TopCenter),
-            horizontalArrangement = Arrangement.Start,
-            content = { content() }
-        )
+            Orientation.Horizontal -> Row(
+                modifier = Modifier
+                    .fillMaxWidth()
+                    .align(Alignment.Center),
+                horizontalArrangement = Arrangement.Center,
+                content = { content() }
+            )
+        }
     }
 }
-//}
 
 @Preview
 @Composable
-fun UserAvatarPreview() {
-    Column {
-        UserAvatar(
-            modifier = Modifier.fillMaxWidth()
-                .background(Color.SuperDarkGray),
-        )
-    }
+fun UserAvatarHorizontalFillPreview() = preview {
+    UserAvatar(
+        modifier = Modifier.fillMaxWidth()
+            .wrapContentHeight()
+            .background(Color.SuperDarkGray),
+        orientation = Orientation.Horizontal,
+    )
+}
+
+@Preview
+@Composable
+fun UserAvatarVerticalPreview() = preview {
+    UserAvatar(
+        modifier = Modifier.fillMaxWidth()
+            .wrapContentHeight()
+            .background(Color.SuperDarkGray),
+        orientation = Orientation.Vertical,
+        textAlign = TextAlign.Center,
+    )
 }

+ 6 - 1
src/main/kotlin/eu/mjdev/desktop/components/video/VideoView.kt

@@ -9,8 +9,10 @@ import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.ColorFilter
 import androidx.compose.ui.layout.ContentScale
 import eu.mjdev.desktop.components.video.base.VideoPlayerFFMpeg
+import eu.mjdev.desktop.extensions.Compose.preview
 import java.io.File
 
+// todo
 @Suppress("UNUSED_PARAMETER", "FunctionName")
 @Preview
 @Composable
@@ -37,6 +39,9 @@ fun VideoView(
     )
 }
 
+// todo
 @Preview
 @Composable
-fun VideoViewPreview() = VideoView()
+fun VideoViewPreview() = preview {
+    VideoView()
+}

+ 5 - 1
src/main/kotlin/eu/mjdev/desktop/components/web/ComposeWebView.kt

@@ -21,6 +21,7 @@ import com.multiplatform.webview.web.WebView
 import com.multiplatform.webview.web.WebViewState
 import eu.mjdev.desktop.components.draggable.DraggableView
 import eu.mjdev.desktop.extensions.Compose.DarkBlue
+import eu.mjdev.desktop.extensions.Compose.preview
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 // todo improve
@@ -97,6 +98,9 @@ fun ComposeWebView(
     }
 }
 
+// todo
 @Preview
 @Composable
-fun ComposeWebViewPreview() = ComposeWebView()
+fun ComposeWebViewPreview() = preview {
+    ComposeWebView()
+}

+ 7 - 1
src/main/kotlin/eu/mjdev/desktop/data/App.kt

@@ -168,7 +168,13 @@ class App(
     }
 
     companion object {
-        val Test = App(DesktopFile.Test)
+        val Test = App(
+            desktopFile = DesktopFile.Test,
+            isFavorite = true,
+        ).apply {
+            isStartingState.value = true
+        }
+
         val Empty: App = App()
 
         fun List<String>?.ifEmptyCategories(block: () -> List<String>) = this?.filter { s ->

+ 15 - 0
src/main/kotlin/eu/mjdev/desktop/data/ItemWithDate.kt

@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package eu.mjdev.desktop.data
+
+import java.util.*
+
+interface ItemWithDate {
+    val date: Date
+}

+ 13 - 0
src/main/kotlin/eu/mjdev/desktop/data/ItemWithTitle.kt

@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package eu.mjdev.desktop.data
+
+interface ItemWithTitle {
+    val title: String
+}

+ 116 - 1
src/main/kotlin/eu/mjdev/desktop/extensions/Compose.kt

@@ -5,9 +5,10 @@ package eu.mjdev.desktop.extensions
 import androidx.compose.animation.*
 import androidx.compose.animation.core.tween
 import androidx.compose.foundation.ExperimentalFoundationApi
+import androidx.compose.foundation.background
 import androidx.compose.foundation.gestures.detectTapGestures
 import androidx.compose.foundation.gestures.detectVerticalDragGestures
-import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.*
 import androidx.compose.foundation.lazy.LazyListState
 import androidx.compose.foundation.relocation.BringIntoViewResponder
 import androidx.compose.foundation.relocation.bringIntoViewResponder
@@ -40,6 +41,8 @@ import coil3.compose.LocalPlatformContext
 import coil3.memory.MemoryCache
 import coil3.request.CachePolicy
 import coil3.svg.SvgDecoder
+import eu.mjdev.desktop.components.guide.GuideLines
+import eu.mjdev.desktop.extensions.ColorUtils.alpha
 import eu.mjdev.desktop.helpers.compose.FocusHelper
 import eu.mjdev.desktop.provider.DesktopProvider
 import eu.mjdev.desktop.provider.DesktopProvider.Companion.LocalDesktop
@@ -48,7 +51,11 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
+import java.lang.reflect.Modifier.isStatic
 import kotlin.coroutines.CoroutineContext
+import kotlin.reflect.KFunction
+import kotlin.reflect.jvm.javaMethod
+import kotlin.reflect.jvm.kotlinFunction
 
 object Compose {
 
@@ -475,6 +482,114 @@ object Compose {
         }
     }
 
+    fun getFunctionFromFile(
+        fileName: String,
+        funcName: String
+    ): KFunction<*>? {
+        val selfRef = ::getFunctionFromFile
+        val currentClass = selfRef.javaMethod?.declaringClass
+        val classDefiningFunctions = currentClass?.classLoader?.loadClass("${fileName}Kt")
+        val javaMethod = classDefiningFunctions?.methods?.find {
+            it.name == funcName && isStatic(it.modifiers)
+        }
+        return javaMethod?.kotlinFunction
+    }
+
+    fun Modifier.size(width: Int, height: Int) = size(width.dp, height.dp)
+
+    fun Modifier.size(value: Int) = size(value.dp, value.dp)
+
+    @Composable
+    fun preview(
+        isDark: Boolean = true,
+        showGuide: Boolean = true,
+        guideStepY: Dp = 8.dp,
+        guideStepX: Dp = 8.dp,
+        guideAlpha: Float = 0.3f,
+        backgroundColor: Color = if (isDark) Color.SuperDarkGray else Color.White,
+        guideLinesColor: Color = if (isDark) Color.White else Color.SuperDarkGray,
+        gravity: Alignment = Alignment.Center,
+        padding: PaddingValues = PaddingValues(16.dp),
+        content: @Composable BoxScope.() -> Unit = {}
+    ) = BoxWithConstraints(
+        modifier = Modifier.fillMaxSize()
+            .background(backgroundColor),
+        contentAlignment = gravity,
+    ) {
+        GuideLines(
+            modifier = Modifier.fillMaxSize(),
+            color = guideLinesColor.alpha(guideAlpha),
+            cellSize = DpSize(guideStepX, guideStepY),
+            visible = showGuide
+        )
+        Box(
+            modifier = Modifier.padding(padding)
+        ) {
+            content()
+        }
+    }
+
+    @Composable
+    fun preview(
+        width: Int,
+        height: Int,
+        isDark: Boolean = true,
+        showGuide: Boolean = true,
+        guideStepY: Dp = 8.dp,
+        guideStepX: Dp = 8.dp,
+        guideAlpha: Float = 0.3f,
+        backgroundColor: Color = if (isDark) Color.SuperDarkGray else Color.White,
+        guideLinesColor: Color = if (isDark) Color.White else Color.SuperDarkGray,
+        gravity: Alignment = Alignment.Center,
+        padding: PaddingValues = PaddingValues(16.dp),
+        content: @Composable BoxScope.() -> Unit = {}
+    ) = preview(
+        isDark = isDark,
+        showGuide = showGuide,
+        guideStepY = guideStepY,
+        guideStepX = guideStepX,
+        guideAlpha = guideAlpha,
+        backgroundColor = backgroundColor,
+        guideLinesColor = guideLinesColor,
+        gravity = gravity,
+        padding = padding
+    ) {
+        Box(
+            modifier = Modifier.size(width, height),
+            content = content
+        )
+    }
+
+    @Composable
+    fun preview(
+        size: Int,
+        isDark: Boolean = true,
+        showGuide: Boolean = true,
+        guideStepY: Dp = 8.dp,
+        guideStepX: Dp = 8.dp,
+        guideAlpha: Float = 0.3f,
+        backgroundColor: Color = if (isDark) Color.SuperDarkGray else Color.White,
+        guideLinesColor: Color = if (isDark) Color.White else Color.SuperDarkGray,
+        gravity: Alignment = Alignment.Center,
+        padding: PaddingValues = PaddingValues(16.dp),
+        content: @Composable BoxScope.() -> Unit = {}
+    ) = preview(
+        isDark = isDark,
+        showGuide = showGuide,
+        guideStepY = guideStepY,
+        guideStepX = guideStepX,
+        guideAlpha = guideAlpha,
+        backgroundColor = backgroundColor,
+        guideLinesColor = guideLinesColor,
+        gravity = gravity,
+        padding = padding
+    ) {
+        Box(
+            modifier = Modifier.size(size, size),
+            content = content
+        )
+    }
+
 //    @Composable
 //    fun runAsync(
 //        context: CoroutineContext = Dispatchers.Main,

+ 1 - 1
src/main/kotlin/eu/mjdev/desktop/icons/Icons.kt

@@ -15,7 +15,7 @@ object Icons {
     val TextSnippet = Icons.AutoMirrored.Filled.TextSnippet
     val Campaign = Icons.Filled.Campaign
     val Chat = Icons.AutoMirrored.Filled.Chat
-    val User = Icons.Filled.AccountCircle
+    val User = Icons.Filled.AccountCircle // import androidx.compose.material.icons.filled.SupervisedUserCircle
     val LogOutUser = Icons.AutoMirrored.Filled.Logout
     val PowerOffComputer = Icons.Filled.PowerOff
     val RestartComputer = Icons.Filled.RestartAlt