cards-native/scripts/make-appicon.swift
Till JS 0b2ae167b7 v0.8.0 — Phase β-7 App-Store-Vorbereitung
Feature-komplett für TestFlight. App-Icon-Platzhalter, Siri-Shortcut,
Share-Extension, Release-Checklist mit allen externen Apple-Schritten.

- scripts/make-appicon.swift: CoreGraphics-basierter Generator für
  1024×1024 forest-green PNG mit "C"-Letter und Karten-Stack-Schatten
- Asset-Catalog auf Single-Size-AppIcon-Pattern umgestellt
- StudyCardsIntent + CardsAppShortcuts (App Intents): Siri-
  Shortcut "Karten lernen mit Cards" / "Mit Cards lernen"
- CardsShareExtension Target: ShareViewController (UIKit-Bootstrap +
  SwiftUI-Hosting), ShareEditorView mit Text-Edit
- PendingShare + PendingShareStore shared in App-Group
  group.ev.mana.cards
- DeckListView zeigt PendingShare-Banner; Tap navigiert zu
  PendingShareConsumeView mit Deck-Picker + Front/Back-Felder, Submit
  → POST /cards, danach store.remove
- Info.plist: NSPhotoLibraryUsageDescription für Image-Occlusion-
  Picker, NSUserActivityTypes für Universal-Links
- docs/RELEASE_CHECKLIST.md mit externen Schritten: Apple-Developer-
  Portal, App-IDs, App-Group, AASA, Xcode-Archive, TestFlight-Plan,
  App-Store-Connect-Felder, Compliance-Verifikation
- UI-Test robuster (akzeptiert Login oder Decks/Entdecken als
  Launch-Erfolg, unabhängig vom Simulator-Keychain-State)
- 35 Tests + 1 UI-Test grün, alle drei Targets bauen

App-Store-Submission selbst ist externe Aktion und passiert nicht
durch dieses Repo — Schritte in docs/RELEASE_CHECKLIST.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 01:13:27 +02:00

82 lines
2.8 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env swift
// Generiert ein 1024×1024-AppIcon-PNG als Platzhalter.
// forest-green Hintergrund + großes weißes "C" mit Karten-Stack-Andeutung.
//
// Aufruf:
// swift scripts/make-appicon.swift
//
// Schreibt nach: Sources/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png
//
// Dies ist ein Platzhalter vor App-Store-Submission durch ein
// professionelles Icon ersetzen (siehe docs/RELEASE_CHECKLIST.md).
import AppKit
import CoreGraphics
let size = 1024
let scale: CGFloat = 1.0
let cs = CGColorSpaceCreateDeviceRGB()
guard let ctx = CGContext(
data: nil,
width: size, height: size,
bitsPerComponent: 8, bytesPerRow: 0,
space: cs,
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue
) else {
print("CGContext creation failed")
exit(1)
}
// HSL(142, 76%, 28%) forest primary light. Hand-konvertiert zu sRGB.
let background = CGColor(red: 0.043, green: 0.494, blue: 0.227, alpha: 1)
ctx.setFillColor(background)
ctx.fill(CGRect(x: 0, y: 0, width: size, height: size))
// Subtile Karten-Stack-Schatten hinter dem C
let shadow1 = CGColor(red: 1, green: 1, blue: 1, alpha: 0.08)
let shadow2 = CGColor(red: 1, green: 1, blue: 1, alpha: 0.05)
let cardW = CGFloat(size) * 0.62
let cardH = CGFloat(size) * 0.82
let cardX = (CGFloat(size) - cardW) / 2
let cardY = (CGFloat(size) - cardH) / 2
ctx.setFillColor(shadow2)
ctx.beginPath()
ctx.addPath(CGPath(roundedRect: CGRect(x: cardX + 30, y: cardY - 30, width: cardW, height: cardH),
cornerWidth: 48, cornerHeight: 48, transform: nil))
ctx.fillPath()
ctx.setFillColor(shadow1)
ctx.beginPath()
ctx.addPath(CGPath(roundedRect: CGRect(x: cardX + 15, y: cardY - 15, width: cardW, height: cardH),
cornerWidth: 48, cornerHeight: 48, transform: nil))
ctx.fillPath()
// Großer weißer "C"-Buchstabe Helvetica-Neue-Bold
let attrs: [NSAttributedString.Key: Any] = [
.font: NSFont(name: "HelveticaNeue-Bold", size: 720) ?? NSFont.boldSystemFont(ofSize: 720),
.foregroundColor: NSColor.white,
]
let str = NSAttributedString(string: "C", attributes: attrs)
let line = CTLineCreateWithAttributedString(str)
let bounds = CTLineGetImageBounds(line, ctx)
let tx = (CGFloat(size) - bounds.width) / 2 - bounds.origin.x
let ty = (CGFloat(size) - bounds.height) / 2 - bounds.origin.y
ctx.textPosition = CGPoint(x: tx, y: ty)
CTLineDraw(line, ctx)
// PNG schreiben
guard let cgImage = ctx.makeImage() else {
print("makeImage failed")
exit(1)
}
let bitmap = NSBitmapImageRep(cgImage: cgImage)
guard let data = bitmap.representation(using: .png, properties: [:]) else {
print("PNG encoding failed")
exit(1)
}
let target = URL(fileURLWithPath: "Sources/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png")
try data.write(to: target)
print("Wrote \(target.path) (\(data.count) bytes)")
_ = scale // suppress unused warning