Jelajahi Sumber

design fixes - basic idea

design fixes - basic idea

design fixes - basic idea
Milan Jurkulak 2 tahun lalu
induk
melakukan
3c3d910a04

+ 2 - 1
src/main/kotlin/eu/mjdev/desktop/components/appbar/AppBar.kt

@@ -21,6 +21,7 @@ import androidx.compose.ui.unit.dp
 fun AppBar(
     modifier: Modifier = Modifier,
     contentPadding: PaddingValues = PaddingValues(4.dp),
+    contentAlignment: Alignment.Vertical = Alignment.CenterVertically,
     iconVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
     titleVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
     actionsVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
@@ -35,7 +36,7 @@ fun AppBar(
         modifier = modifier
             .height(IntrinsicSize.Min)
             .padding(contentPadding),
-        verticalAlignment = Alignment.Bottom,
+        verticalAlignment = contentAlignment,
     ) {
         Row(
             modifier = Modifier.wrapContentHeight()

+ 25 - 11
src/main/kotlin/eu/mjdev/desktop/components/appsmenu/AppsMenu.kt

@@ -14,6 +14,7 @@ import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.layout.onPlaced
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.WindowPosition
@@ -24,6 +25,7 @@ import eu.mjdev.desktop.components.user.UserAvatar
 import eu.mjdev.desktop.data.App
 import eu.mjdev.desktop.data.Category
 import eu.mjdev.desktop.extensions.ColorUtils.alpha
+import eu.mjdev.desktop.extensions.ColorUtils.darker
 import eu.mjdev.desktop.extensions.Compose.clear
 import eu.mjdev.desktop.extensions.Compose.launchedEffect
 import eu.mjdev.desktop.extensions.Compose.onMouseEnter
@@ -38,6 +40,7 @@ import eu.mjdev.desktop.helpers.animation.Animations.AppsMenuEnterAnimation
 import eu.mjdev.desktop.helpers.animation.Animations.AppsMenuExitAnimation
 import eu.mjdev.desktop.helpers.compose.rememberForeverLazyListState
 import eu.mjdev.desktop.helpers.internal.KeyEventHandler.Companion.globalKeyEventHandler
+import eu.mjdev.desktop.helpers.shape.BarShape
 import eu.mjdev.desktop.provider.DesktopScope
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 import eu.mjdev.desktop.windows.ChromeWindow
@@ -154,28 +157,39 @@ fun AppsMenu(
                 Column(
                     modifier = Modifier.fillMaxSize()
                 ) {
-                    BoxWithConstraints(
+                    Box(
+                        modifier = Modifier.clip(RectangleShape),
                         contentAlignment = Alignment.BottomStart
                     ) {
+                        val shape = BarShape(
+                            offset = 52f,
+                            circleRadius = 24.dp,
+                            cornerRadius = 4.dp,
+                            circleGap = 8.dp,
+                        )
+                        val brush = Brush.horizontalGradient(
+                            listOf(
+                                backgroundColor.alpha(1f),
+                                backgroundColor.alpha(1f),
+                                backgroundColor.darker(0.3f),
+                                backgroundColor.alpha(0.9f),
+                                backgroundColor.alpha(0.7f)
+                            ),
+                            startX = 0f,
+                            endX = 0f
+                        )
                         Box(
                             modifier = Modifier.fillMaxWidth()
                                 .height(64.dp)
                                 .background(
-                                    Brush.horizontalGradient(
-                                        listOf(
-                                            backgroundColor.alpha(0.3f),
-                                            backgroundColor,
-                                            backgroundColor.alpha(0.3f)
-                                        ),
-                                        startX = 0f,
-                                        endX = 0f
-                                    )
+                                    brush = brush,
+                                    shape = shape
                                 )
                         )
                         UserAvatar(
                             titleVerticalAlignment = Alignment.Bottom,
                             iconPadding = PaddingValues(bottom = 16.dp),
-                            titlePadding = PaddingValues(bottom = 4.dp),
+                            titlePadding = PaddingValues(top = 24.dp, start = 20.dp),
                             avatarSize = 64.dp,
                             onUserAvatarClick = onUserAvatarClick
                         )

+ 46 - 11
src/main/kotlin/eu/mjdev/desktop/components/controlcenter/pages/MainSettingsPage.kt

@@ -9,6 +9,9 @@ import androidx.compose.material.icons.filled.Home
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.RectangleShape
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import eu.mjdev.desktop.components.controlcenter.base.ControlCenterPage
@@ -16,8 +19,10 @@ import eu.mjdev.desktop.components.custom.DateTime
 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.runAsync
 import eu.mjdev.desktop.extensions.Modifier.rectShadow
+import eu.mjdev.desktop.helpers.shape.BarShape
 
 @Suppress("FunctionName")
 fun MainSettingsPage() = ControlCenterPage(
@@ -32,21 +37,51 @@ fun MainSettingsPage() = ControlCenterPage(
             modifier = Modifier
                 .fillMaxWidth()
                 .align(Alignment.TopCenter)
-                .rectShadow(8.dp, borderColor.copy(alpha = 0.3f))
         ) {
-            UserAvatar(
-                modifier = Modifier.background(backgroundColor),
-                avatarSize = 96.dp,
-                titleTextSize = 20.sp,
-                detailTextSize = 16.sp,
-                onUserAvatarClick = {
-                    // todo
-                }
-            )
+            Box(
+                modifier = Modifier.clip(RectangleShape),
+                contentAlignment = Alignment.BottomStart
+            ) {
+                val shape = BarShape(
+                    offset = 68f,
+                    circleRadius = 52.dp,
+                    cornerRadius = 0.dp,
+                    circleGap = 4.dp,
+                )
+                val brush = Brush.horizontalGradient(
+                    listOf(
+                        backgroundColor.alpha(1f),
+                        backgroundColor.alpha(1f),
+                        backgroundColor.darker(0.3f),
+                        backgroundColor.alpha(0.9f),
+                        backgroundColor.alpha(0.7f)
+                    ),
+                    startX = 0f,
+                    endX = 0f
+                )
+                Box(
+                    modifier = Modifier
+                        .fillMaxWidth()
+                        .height(64.dp)
+                        .background(
+                            brush = brush,
+                            shape = shape
+                        )
+                )
+                UserAvatar(
+                    avatarSize = 96.dp,
+                    titleTextSize = 20.sp,
+                    detailTextSize = 16.sp,
+                    titleHorizontalAlignment = Alignment.CenterHorizontally,
+                    onUserAvatarClick = {
+                        // todo
+                    }
+                )
+            }
             Divider(
                 modifier = Modifier.fillMaxWidth()
                     .height(2.dp),
-                color = borderColor,
+                color = borderColor.alpha(0.5f),
                 thickness = 2.dp
             )
             DateTime(

+ 10 - 3
src/main/kotlin/eu/mjdev/desktop/components/custom/PowerBlock.kt

@@ -22,12 +22,13 @@ import eu.mjdev.desktop.extensions.Modifier.circleBorder
 import eu.mjdev.desktop.extensions.Modifier.circleShadow
 import eu.mjdev.desktop.extensions.Modifier.clipCircle
 import eu.mjdev.desktop.extensions.Modifier.rectShadow
+import eu.mjdev.desktop.helpers.shape.BarShape
 import eu.mjdev.desktop.provider.DesktopScope.Companion.withDesktopScope
 
 // todo shadow? background?
 @Composable
 fun PowerBlock(
-    backgroundColor: Color=Color.Transparent,
+    backgroundColor: Color = Color.Transparent,
     shadowColor: Color = Color.Black.copy(alpha = 0.3f),
     iconTintColor: Color = Color.Black,
     bottomBoxHeight: Dp = 128.dp,
@@ -37,18 +38,24 @@ fun PowerBlock(
     Column(
         modifier = Modifier.fillMaxWidth()
     ) {
-        Box(
+        BoxWithConstraints(
             modifier = Modifier
                 .fillMaxWidth()
                 .height(bottomBoxHeight),
             contentAlignment = Alignment.BottomCenter
         ) {
+            val shape = BarShape(
+                offset = (minWidth / 2).value,
+                circleRadius = 24.dp,
+                cornerRadius = 4.dp,
+                circleGap = 8.dp,
+            )
             Box(
                 modifier = Modifier
                     .fillMaxWidth()
                     .height(iconHeight)
                     .rectShadow(color = shadowColor)
-                    .background(backgroundColor)
+                    .background(backgroundColor, shape)
             )
             Button(
                 modifier = Modifier

+ 13 - 11
src/main/kotlin/eu/mjdev/desktop/components/user/UserAvatar.kt

@@ -42,9 +42,10 @@ fun UserAvatar(
     iconVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
     titleVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
     actionsVerticalAlignment: Alignment.Vertical = Alignment.CenterVertically,
-    iconPadding : PaddingValues = PaddingValues(),
-    titlePadding : PaddingValues = PaddingValues(),
-    actionsPadding : PaddingValues = PaddingValues(),
+    titleHorizontalAlignment: Alignment.Horizontal = Alignment.Start,
+    iconPadding: PaddingValues = PaddingValues(),
+    titlePadding: PaddingValues = PaddingValues(),
+    actionsPadding: PaddingValues = PaddingValues(),
     onUserAvatarClick: () -> Unit = {},
     actions: @Composable RowScope.() -> Unit = {},
 ) = withDesktopScope {
@@ -53,6 +54,7 @@ fun UserAvatar(
             iconVerticalAlignment = iconVerticalAlignment,
             titleVerticalAlignment = titleVerticalAlignment,
             actionsVerticalAlignment = actionsVerticalAlignment,
+            contentAlignment = Alignment.Bottom,
             iconPadding = iconPadding,
             titlePadding = titlePadding,
             actionsPadding = actionsPadding,
@@ -80,7 +82,7 @@ fun UserAvatar(
                         .fillMaxWidth()
                         .padding(top = 8.dp),
                     verticalArrangement = Arrangement.Center,
-                    horizontalAlignment = Alignment.Start
+                    horizontalAlignment = titleHorizontalAlignment
                 ) {
                     TextAny(
                         text = api.currentUser.userName,
@@ -117,14 +119,14 @@ fun UserAvatar(
 
 //            Orientation.Horizontal ->
         Row(
-                modifier = Modifier
-                    .fillMaxWidth()
-                    .align(Alignment.TopCenter),
-                horizontalArrangement = Arrangement.Start,
-                content = { content() }
-            )
-        }
+            modifier = Modifier
+                .fillMaxWidth()
+                .align(Alignment.TopCenter),
+            horizontalArrangement = Arrangement.Start,
+            content = { content() }
+        )
     }
+}
 //}
 
 @Preview

+ 92 - 0
src/main/kotlin/eu/mjdev/desktop/helpers/shape/BarShape.kt

@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) Milan Jurkulák 2024.
+ *  Contact:
+ *  e: mimoccc@gmail.com
+ *  e: mj@mjdev.org
+ *  w: https://mjdev.org
+ */
+
+package eu.mjdev.desktop.helpers.shape
+
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.Outline
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.unit.Density
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.LayoutDirection
+import androidx.compose.ui.unit.dp
+
+// todo : shadow
+class BarShape(
+    private val offset: Float,
+    private val circleRadius: Dp,
+    private val cornerRadius: Dp,
+    private val circleGap: Dp = 5.dp,
+) : Shape {
+    override fun createOutline(
+        size: Size, layoutDirection: LayoutDirection, density: Density
+    ): Outline {
+        return Outline.Generic(getPath(size, density))
+    }
+
+    private fun getPath(size: Size, density: Density): Path {
+        val cutoutCenterX = offset
+        val cutoutRadius = density.run { (circleRadius + circleGap).toPx() }
+        val cornerRadiusPx = density.run { cornerRadius.toPx() }
+        val cornerDiameter = cornerRadiusPx * 2
+        return Path().apply {
+            val cutoutEdgeOffset = cutoutRadius * 2.5f
+            val cutoutLeftX = cutoutCenterX - cutoutEdgeOffset
+            val cutoutRightX = cutoutCenterX + cutoutEdgeOffset
+            moveTo(x = 0F, y = size.height)
+            if (cutoutLeftX > 0) {
+                val realLeftCornerDiameter = if (cutoutLeftX >= cornerRadiusPx) {
+                    cornerDiameter
+                } else {
+                    cutoutLeftX * 2
+                }
+                arcTo(
+                    rect = Rect(
+                        left = 0f, top = 0f, right = realLeftCornerDiameter, bottom = realLeftCornerDiameter
+                    ), startAngleDegrees = 180.0f, sweepAngleDegrees = 90.0f, forceMoveTo = false
+                )
+            }
+            lineTo(cutoutLeftX, 0f)
+            cubicTo(
+                x1 = cutoutCenterX - cutoutRadius,
+                y1 = 0f,
+                x2 = cutoutCenterX - cutoutRadius,
+                y2 = cutoutRadius,
+                x3 = cutoutCenterX,
+                y3 = cutoutRadius,
+            )
+            cubicTo(
+                x1 = cutoutCenterX + cutoutRadius,
+                y1 = cutoutRadius,
+                x2 = cutoutCenterX + cutoutRadius,
+                y2 = 0f,
+                x3 = cutoutRightX,
+                y3 = 0f,
+            )
+            if (cutoutRightX < size.width) {
+                val realRightCornerDiameter = if (cutoutRightX <= size.width - cornerRadiusPx) {
+                    cornerDiameter
+                } else {
+                    (size.width - cutoutRightX) * 2
+                }
+                arcTo(
+                    rect = Rect(
+                        left = size.width - realRightCornerDiameter,
+                        top = 0f,
+                        right = size.width,
+                        bottom = realRightCornerDiameter
+                    ), startAngleDegrees = -90.0f, sweepAngleDegrees = 90.0f, forceMoveTo = false
+                )
+            }
+            lineTo(x = size.width, y = size.height)
+            close()
+        }
+    }
+}