From a2293c5609ee7b5b7bbfce3b4c0dc7ae365e31ff Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Sat, 13 Jun 2026 20:52:55 +0800
Subject: [PATCH] Fix Finder split view tab activation regression

---
 C3.tools/generate-app-icon.py |  269 +++++++++++------------------------------------------
 1 files changed, 55 insertions(+), 214 deletions(-)

diff --git a/C3.tools/generate-app-icon.py b/C3.tools/generate-app-icon.py
index bb01b28..d75bc57 100755
--- a/C3.tools/generate-app-icon.py
+++ b/C3.tools/generate-app-icon.py
@@ -1,241 +1,82 @@
 #!/usr/bin/env python3
-"""Generate Aligner's macOS app icon assets."""
+"""Sync Aligner's macOS app icon assets from the design handoff."""
 
 from __future__ import annotations
 
 import json
 import shutil
-import subprocess
 from pathlib import Path
 
-from PIL import Image, ImageDraw, ImageFilter
 
-
-ROOT = Path(__file__).resolve().parents[1]
-RESOURCES = ROOT / "C1.source" / "Resources"
+OUTPUT_ROOT = Path(__file__).resolve().parents[1]
+PROJECT_ROOT = OUTPUT_ROOT.parent
+RESOURCES = OUTPUT_ROOT / "C1.source" / "Resources"
 APPICONSET = RESOURCES / "Assets.xcassets" / "AppIcon.appiconset"
 ICNS_PATH = RESOURCES / "AppIcon.icns"
 
-BASE_SIZE = 1024
-SCALE = 4
-CANVAS_SIZE = BASE_SIZE * SCALE
+HANDOFF_DIR = (
+    PROJECT_ROOT
+    / "02-P"
+    / "Round01-QuickSwitch-MVP"
+    / "02.ui设计稿"
+    / "AppIcon-D1-BigBars-Handoff-20260604"
+)
+HANDOFF_ICONSET = HANDOFF_DIR / "AppIcon-D1-BigBars.iconset"
+HANDOFF_ICNS = HANDOFF_DIR / "Aligner-AppIcon-D1-BigBars.icns"
+HANDOFF_PREVIEW = HANDOFF_DIR / "Aligner-AppIcon-D1-BigBars-1024.png"
+
+ICON_FILES = [
+    "icon_16x16.png",
+    "icon_16x16@2x.png",
+    "icon_32x32.png",
+    "icon_32x32@2x.png",
+    "icon_128x128.png",
+    "icon_128x128@2x.png",
+    "icon_256x256.png",
+    "icon_256x256@2x.png",
+    "icon_512x512.png",
+    "icon_512x512@2x.png",
+]
 
 
-def s(value: float) -> int:
-    return round(value * SCALE)
+def require_file(path: Path) -> None:
+    if not path.is_file():
+        raise FileNotFoundError(f"missing app icon source: {path}")
 
 
-def sb(bbox: tuple[float, float, float, float]) -> tuple[int, int, int, int]:
-    return tuple(s(value) for value in bbox)
+def load_contents_json() -> dict:
+    contents_path = HANDOFF_ICONSET / "Contents.json"
+    require_file(contents_path)
+    with contents_path.open("r", encoding="utf-8") as file:
+        return json.load(file)
 
 
-def rounded_mask(size: tuple[int, int], bbox: tuple[int, int, int, int], radius: int) -> Image.Image:
-    mask = Image.new("L", size, 0)
-    ImageDraw.Draw(mask).rounded_rectangle(bbox, radius=radius, fill=255)
-    return mask
-
-
-def composite_masked(base: Image.Image, layer: Image.Image, mask: Image.Image) -> None:
-    base.alpha_composite(Image.composite(layer, Image.new("RGBA", base.size), mask))
-
-
-def vertical_gradient(
-    size: tuple[int, int],
-    top: tuple[int, int, int, int],
-    bottom: tuple[int, int, int, int],
-) -> Image.Image:
-    image = Image.new("RGBA", size)
-    draw = ImageDraw.Draw(image)
-    height = max(size[1] - 1, 1)
-    for y in range(size[1]):
-        t = y / height
-        color = tuple(round(top[i] * (1 - t) + bottom[i] * t) for i in range(4))
-        draw.line((0, y, size[0], y), fill=color)
-    return image
-
-
-def add_shadow(
-    base: Image.Image,
-    mask: Image.Image,
-    color: tuple[int, int, int, int],
-    blur: int,
-    dx: int,
-    dy: int,
-) -> None:
-    shadow_mask = mask.filter(ImageFilter.GaussianBlur(blur))
-    shifted = Image.new("L", base.size, 0)
-    shifted.paste(shadow_mask, (dx, dy))
-    composite_masked(base, Image.new("RGBA", base.size, color), shifted)
-
-
-def draw_outer_shell(canvas: Image.Image) -> None:
-    bbox = sb((78, 58, 946, 934))
-    radius = s(206)
-    mask = rounded_mask(canvas.size, bbox, radius)
-
-    add_shadow(canvas, mask, (55, 72, 98, 22), s(16), 0, s(16))
-    add_shadow(canvas, mask, (255, 255, 255, 135), s(8), 0, s(-5))
-
-    shell_fill = vertical_gradient(
-        canvas.size,
-        (253, 254, 255, 250),
-        (228, 236, 246, 247),
-    )
-    composite_masked(canvas, shell_fill, mask)
-
-    edge = ImageDraw.Draw(canvas)
-    edge.rounded_rectangle(bbox, radius=radius, outline=(255, 255, 255, 226), width=s(7))
-    edge.rounded_rectangle(
-        sb((90, 70, 934, 922)),
-        radius=radius - s(12),
-        outline=(255, 255, 255, 85),
-        width=s(2),
-    )
-    edge.rounded_rectangle(bbox, radius=radius, outline=(168, 184, 206, 32), width=s(2))
-
-
-def draw_capsule(
-    canvas: Image.Image,
-    bbox: tuple[int, int, int, int],
-    top: tuple[int, int, int, int],
-    bottom: tuple[int, int, int, int],
-    outer_edge: tuple[int, int, int, int],
-    shadow_color: tuple[int, int, int, int],
-    shadow_blur: int,
-    is_accent: bool = False,
-) -> None:
-    radius = (bbox[2] - bbox[0]) // 2
-    mask = rounded_mask(canvas.size, bbox, radius)
-
-    add_shadow(canvas, mask, shadow_color, shadow_blur, 0, s(16 if not is_accent else 18))
-    fill = vertical_gradient(canvas.size, top, bottom)
-    composite_masked(canvas, fill, mask)
-
-    draw = ImageDraw.Draw(canvas)
-    draw.rounded_rectangle(bbox, radius=radius, outline=(255, 255, 255, 218), width=s(6))
-    draw.rounded_rectangle(
-        (bbox[0] + s(8), bbox[1] + s(8), bbox[2] - s(8), bbox[3] - s(8)),
-        radius=radius - s(9),
-        outline=(255, 255, 255, 102 if not is_accent else 76),
-        width=s(2),
-    )
-    draw.rounded_rectangle(bbox, radius=radius, outline=outer_edge, width=s(2))
-
-    if not is_accent:
-        shade = Image.new("RGBA", canvas.size, (0, 0, 0, 0))
-        shade_draw = ImageDraw.Draw(shade)
-        shade_draw.rounded_rectangle(
-            (bbox[0] + s(7), bbox[1] + s(12), bbox[0] + s(30), bbox[3] - s(12)),
-            radius=radius // 2,
-            fill=(136, 158, 184, 22),
-        )
-        composite_masked(canvas, shade, mask)
-
-
-def draw_icon() -> Image.Image:
-    canvas = Image.new("RGBA", (CANVAS_SIZE, CANVAS_SIZE), (0, 0, 0, 0))
-    draw_outer_shell(canvas)
-
-    left_bar = sb((300, 262, 420, 742))
-    middle_bar = sb((452, 262, 572, 742))
-    accent_bar = sb((604, 262, 724, 742))
-
-    neutral_edge = (136, 158, 184, 58)
-    draw_capsule(
-        canvas,
-        left_bar,
-        (238, 245, 252, 226),
-        (228, 237, 247, 226),
-        neutral_edge,
-        (136, 158, 184, 58),
-        s(36),
-    )
-    draw_capsule(
-        canvas,
-        middle_bar,
-        (232, 241, 249, 232),
-        (222, 234, 246, 232),
-        neutral_edge,
-        (136, 158, 184, 66),
-        s(38),
-    )
-    draw_capsule(
-        canvas,
-        accent_bar,
-        (75, 183, 255, 238),
-        (20, 145, 255, 238),
-        (28, 133, 255, 72),
-        (25, 118, 210, 62),
-        s(20),
-        is_accent=True,
-    )
-
-    return canvas.resize((BASE_SIZE, BASE_SIZE), Image.Resampling.LANCZOS)
-
-
-def write_contents_json() -> None:
-    entries = [
-        ("16x16", "1x", "icon_16x16.png"),
-        ("16x16", "2x", "icon_16x16@2x.png"),
-        ("32x32", "1x", "icon_32x32.png"),
-        ("32x32", "2x", "icon_32x32@2x.png"),
-        ("128x128", "1x", "icon_128x128.png"),
-        ("128x128", "2x", "icon_128x128@2x.png"),
-        ("256x256", "1x", "icon_256x256.png"),
-        ("256x256", "2x", "icon_256x256@2x.png"),
-        ("512x512", "1x", "icon_512x512.png"),
-        ("512x512", "2x", "icon_512x512@2x.png"),
-    ]
-    payload = {
-        "images": [
-            {"filename": filename, "idiom": "mac", "scale": scale, "size": size}
-            for size, scale, filename in entries
-        ],
-        "info": {"author": "xcode", "version": 1},
-    }
-    (APPICONSET / "Contents.json").write_text(json.dumps(payload, indent=2) + "\n")
-
-
-def write_icon_family(source: Image.Image) -> None:
-    sizes = {
-        "icon_16x16.png": 16,
-        "icon_16x16@2x.png": 32,
-        "icon_32x32.png": 32,
-        "icon_32x32@2x.png": 64,
-        "icon_128x128.png": 128,
-        "icon_128x128@2x.png": 256,
-        "icon_256x256.png": 256,
-        "icon_256x256@2x.png": 512,
-        "icon_512x512.png": 512,
-        "icon_512x512@2x.png": 1024,
-    }
-
+def sync_iconset() -> None:
     APPICONSET.mkdir(parents=True, exist_ok=True)
-    source.save(APPICONSET / "icon_1024_preview.png")
-    for filename, size in sizes.items():
-        source.resize((size, size), Image.Resampling.LANCZOS).save(APPICONSET / filename)
+    contents = load_contents_json()
+
+    for filename in ICON_FILES:
+        source = HANDOFF_ICONSET / filename
+        require_file(source)
+        shutil.copy2(source, APPICONSET / filename)
+
+    require_file(HANDOFF_PREVIEW)
+    shutil.copy2(HANDOFF_PREVIEW, APPICONSET / "icon_1024_preview.png")
+
+    with (APPICONSET / "Contents.json").open("w", encoding="utf-8") as file:
+        json.dump(contents, file, indent=2, ensure_ascii=False)
+        file.write("\n")
 
 
-def write_icns() -> None:
-    iconset = RESOURCES / "AppIcon.iconset"
-    if iconset.exists():
-        shutil.rmtree(iconset)
-    iconset.mkdir()
-
-    for icon in APPICONSET.glob("icon_*.png"):
-        if icon.name == "icon_1024_preview.png":
-            continue
-        shutil.copy2(icon, iconset / icon.name)
-
-    subprocess.run(["iconutil", "-c", "icns", str(iconset), "-o", str(ICNS_PATH)], check=True)
-    shutil.rmtree(iconset)
+def sync_icns() -> None:
+    require_file(HANDOFF_ICNS)
+    shutil.copy2(HANDOFF_ICNS, ICNS_PATH)
 
 
 def main() -> None:
-    icon = draw_icon()
-    write_icon_family(icon)
-    write_contents_json()
-    write_icns()
+    sync_iconset()
+    sync_icns()
+    print(f"Synced AppIcon assets from: {HANDOFF_DIR}")
 
 
 if __name__ == "__main__":

--
Gitblit v1.9.3