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>
This commit is contained in:
parent
55359c5333
commit
0b2ae167b7
16 changed files with 783 additions and 59 deletions
82
scripts/make-appicon.swift
Normal file
82
scripts/make-appicon.swift
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
#!/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
|
||||
Loading…
Add table
Add a link
Reference in a new issue