From 66dd5ed6e60547629b9cf91431d030d75886aef8 Mon Sep 17 00:00:00 2001
From: Yiqun Zhang <guiyanakuang@gmail.com>
Date: Fri, 24 Nov 2023 16:54:13 +0800
Subject: [PATCH] :bug: Avoid jagged graphics by using native rounded corners

---
 .../kotlin/com/clipevery/ClipeveryApp.kt      | 45 ++++++++++++-
 .../desktopMain/kotlin/com/clipevery/main.kt  | 65 ++++---------------
 2 files changed, 56 insertions(+), 54 deletions(-)

diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt
index b06fb58bf..a2f612c68 100644
--- a/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt
+++ b/composeApp/src/commonMain/kotlin/com/clipevery/ClipeveryApp.kt
@@ -2,6 +2,7 @@ package com.clipevery
 
 import androidx.compose.desktop.ui.tooling.preview.Preview
 import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
@@ -15,8 +16,10 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.layout.wrapContentWidth
+import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material.Icon
 import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Surface
 import androidx.compose.material.Text
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
@@ -28,6 +31,8 @@ import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
 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.Color
 import androidx.compose.ui.graphics.ImageBitmap
 import androidx.compose.ui.graphics.toComposeImageBitmap
@@ -42,7 +47,10 @@ import kotlinx.coroutines.launch
 @Composable
 fun ClipeveryApp(dependencies: Dependencies) {
     MaterialTheme {
-        Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
+        Column(Modifier.fillMaxWidth()
+            .clip(RoundedCornerShape(10.dp))
+            .background(Color.White),
+            horizontalAlignment = Alignment.CenterHorizontally) {
             ClipeveryCommon(dependencies)
         }
     }
@@ -65,9 +73,8 @@ fun ClipeveryCommon(dependencies: Dependencies) {
 @Composable
 fun ClipeveryWithProvidedDependencies() {
     val configManager = LocalConfigManager.current
-
     val config = remember { mutableStateOf(configManager.config) }
-
+    CustomWindowDecoration()
     if (!config.value.bindingState) {
         bindingQRCode()
     } else {
@@ -75,6 +82,38 @@ fun ClipeveryWithProvidedDependencies() {
     }
 }
 
+@Composable
+fun CustomWindowDecoration() {
+    Surface(
+        modifier = Modifier
+            .fillMaxWidth()
+            .height(62.dp),
+        color = MaterialTheme.colors.background,
+        shape = RoundedCornerShape(
+            topStart = 10.dp,
+            topEnd = 10.dp,
+            bottomEnd = 0.dp,
+            bottomStart = 0.dp
+        )
+    ) {
+        Box(
+            modifier = Modifier.background(Color.Black)
+                .background(
+                    brush = Brush.verticalGradient(
+                        colors = listOf(
+                            Color.White.copy(alpha = 0.6f),
+                            Color.Transparent
+                        ),
+                        startY = 0.0f,
+                        endY = 3.0f
+                    )
+                ),
+        ) {
+            // Custom title bar content
+        }
+    }
+}
+
 
 @Composable
 fun bindingQRCode() {
diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/main.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/main.kt
index 193b6b033..e27151f43 100644
--- a/composeApp/src/desktopMain/kotlin/com/clipevery/main.kt
+++ b/composeApp/src/desktopMain/kotlin/com/clipevery/main.kt
@@ -1,25 +1,13 @@
 package com.clipevery
 
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Surface
-import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
 import androidx.compose.ui.awt.ComposeWindow
-import androidx.compose.ui.graphics.Brush
-import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.unit.dp
 import androidx.compose.ui.window.Tray
 import androidx.compose.ui.window.Window
 import androidx.compose.ui.window.WindowPlacement
@@ -50,7 +38,8 @@ import com.clipevery.utils.initAppUI
 import com.clipevery.utils.ioDispatcher
 import io.github.oshai.kotlinlogging.KotlinLogging
 import kotlinx.coroutines.CoroutineScope
-import java.awt.geom.RoundRectangle2D
+import java.awt.Rectangle
+import java.awt.geom.Area
 import java.nio.file.Path
 import kotlin.io.path.pathString
 
@@ -86,7 +75,8 @@ fun main() = application {
         size = getPreferredWindowSize(appUI)
     )
 
-    Tray(icon = trayIcon,
+    Tray(
+        icon = trayIcon,
         mouseListener = getTrayMouseAdapter(windowState) { showWindow = !showWindow },
     )
 
@@ -104,7 +94,7 @@ fun main() = application {
         LaunchedEffect(Unit) {
             window.addComponentListener(object : java.awt.event.ComponentAdapter() {
                 override fun componentResized(e: java.awt.event.ComponentEvent?) {
-                    applyRoundedCorners(window)
+                    setWindowShapeWithTransparentEdges(window, 10)
                 }
             })
             window.addWindowFocusListener(object : java.awt.event.WindowFocusListener {
@@ -117,48 +107,21 @@ fun main() = application {
                 }
             })
         }
-        CustomWindowDecoration()
         ClipeveryApp(dependencies)
     }
 }
 
 
-@Composable
-fun CustomWindowDecoration() {
-    Surface(
-        modifier = Modifier
-            .fillMaxWidth()
-            .height(62.dp),
-        color = MaterialTheme.colors.background,
-        shape = RoundedCornerShape(
-            topStart = 10.dp,
-            topEnd = 10.dp,
-            bottomEnd = 0.dp,
-            bottomStart = 0.dp
-        )
-    ) {
-        Box(
-            modifier = Modifier.background(Color.Black)
-                .background(
-                    brush = Brush.verticalGradient(
-                        colors = listOf(
-                            Color.White.copy(alpha = 0.6f),
-                            Color.Transparent
-                        ),
-                        startY = 0.0f,
-                        endY = 3.0f
-                    )
-                ),
-        ) {
-            // Custom title bar content
-        }
-    }
-}
 
-fun applyRoundedCorners(window: ComposeWindow) {
-    val radius = 20.0
-    val shape = RoundRectangle2D.Double(0.0, 0.0, window.width.toDouble(), window.height.toDouble(), radius, radius)
-    window.shape = shape
+
+fun setWindowShapeWithTransparentEdges(window: ComposeWindow, transparentHeight: Int) {
+    val originalRect = Rectangle(0, 0, window.width, window.height)
+    val area = Area(originalRect)
+    val topRect = Rectangle(0, 0, window.width, transparentHeight)
+    val bottomRect = Rectangle(0, window.height - transparentHeight, window.width, transparentHeight)
+    area.subtract(Area(topRect))
+    area.subtract(Area(bottomRect))
+    window.shape = area
 }