Icon and app name

This commit is contained in:
Rukira 2026-03-04 16:18:25 +00:00
parent 910fbc3497
commit 8a437abb0f
2 changed files with 64 additions and 32 deletions

View file

@ -69,8 +69,16 @@ compose.desktop {
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "com.rukira.wowbackup"
packageName = "WoW Backup"
packageVersion = appVersion
macOS {
bundleID = "com.rukira.wowbackup"
}
windows {
upgradeUuid = "e5a8b2c4-1f3d-4a6e-9b7c-2d8f0e1a3b5c"
}
}
}
}

View file

@ -1,45 +1,69 @@
package com.rukira.wowbackup.ui
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.toComposeImageBitmap
import java.awt.BasicStroke
import java.awt.Graphics2D
import java.awt.RenderingHints
import java.awt.geom.GeneralPath
import java.awt.image.BufferedImage
/**
* A simple shield-shaped tray icon drawn in code.
* A simple shield-shaped tray icon with a "W" letter inside.
* Rendered via Java2D BufferedImage for reliable AWT system tray display.
* Works with macOS template images (-Dapple.awt.enableTemplateImages=true)
* which will automatically adapt to dark/light menu bar.
*/
fun trayIconPainter(): Painter = object : Painter() {
override val intrinsicSize = Size(32f, 32f)
fun trayIconPainter(): Painter {
val size = 128
val img = BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB)
val g: Graphics2D = img.createGraphics()
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY)
override fun DrawScope.onDraw() {
val w = size.width
val h = size.height
val w = size.toFloat()
val h = size.toFloat()
// Shield shape
val shield = Path().apply {
moveTo(w * 0.5f, h * 0.05f)
lineTo(w * 0.9f, h * 0.2f)
lineTo(w * 0.9f, h * 0.5f)
cubicTo(w * 0.9f, h * 0.75f, w * 0.5f, h * 0.95f, w * 0.5f, h * 0.95f)
cubicTo(w * 0.5f, h * 0.95f, w * 0.1f, h * 0.75f, w * 0.1f, h * 0.5f)
lineTo(w * 0.1f, h * 0.2f)
close()
}
drawPath(shield, Color.Black)
// Checkmark inside the shield
val check = Path().apply {
moveTo(w * 0.25f, h * 0.48f)
lineTo(w * 0.42f, h * 0.65f)
lineTo(w * 0.72f, h * 0.32f)
}
drawPath(
check,
Color.White,
style = androidx.compose.ui.graphics.drawscope.Stroke(width = w * 0.08f),
// Shield shape (filled black)
val shield = GeneralPath().apply {
moveTo((w * 0.5f).toDouble(), (h * 0.05f).toDouble())
lineTo((w * 0.9f).toDouble(), (h * 0.2f).toDouble())
lineTo((w * 0.9f).toDouble(), (h * 0.5f).toDouble())
curveTo(
(w * 0.9f).toDouble(), (h * 0.75f).toDouble(),
(w * 0.5f).toDouble(), (h * 0.95f).toDouble(),
(w * 0.5f).toDouble(), (h * 0.95f).toDouble(),
)
curveTo(
(w * 0.5f).toDouble(), (h * 0.95f).toDouble(),
(w * 0.1f).toDouble(), (h * 0.75f).toDouble(),
(w * 0.1f).toDouble(), (h * 0.5f).toDouble(),
)
lineTo((w * 0.1f).toDouble(), (h * 0.2f).toDouble())
closePath()
}
// Create the "W" stroke shape to carve out of the shield
val letterW = GeneralPath().apply {
moveTo((w * 0.22f).toDouble(), (h * 0.30f).toDouble())
lineTo((w * 0.35f).toDouble(), (h * 0.70f).toDouble())
lineTo((w * 0.50f).toDouble(), (h * 0.45f).toDouble())
lineTo((w * 0.65f).toDouble(), (h * 0.70f).toDouble())
lineTo((w * 0.78f).toDouble(), (h * 0.30f).toDouble())
}
val wStroke = BasicStroke(w * 0.06f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)
val wShape = wStroke.createStrokedShape(letterW)
// Subtract the W from the shield using Area
val shieldArea = java.awt.geom.Area(shield)
shieldArea.subtract(java.awt.geom.Area(wShape))
g.color = java.awt.Color.BLACK
g.fill(shieldArea)
g.dispose()
return BitmapPainter(img.toComposeImageBitmap())
}