Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
657ca6bc5c
commit
635751f906
@ -14,9 +14,20 @@ public struct IconGeneratorView: View {
|
||||
let config: AppIconConfig
|
||||
let appName: String
|
||||
|
||||
@State private var status: String = "Tap the button to generate the icon"
|
||||
@State private var status: String = "Tap the button to generate all icon variants"
|
||||
@State private var isGenerating = false
|
||||
@State private var generatedIcon: GeneratedIconInfo?
|
||||
@State private var generatedIcons: [GeneratedIconInfo] = []
|
||||
|
||||
// Standard iOS icon sizes (points)
|
||||
private let iconSizes: [(size: CGFloat, scales: [Int], name: String)] = [
|
||||
(20, [2, 3], "Notification"),
|
||||
(29, [2, 3], "Settings"),
|
||||
(40, [2, 3], "Spotlight"),
|
||||
(60, [2, 3], "App"),
|
||||
(76, [1, 2], "iPad App"),
|
||||
(83.5, [2], "iPad Pro App"),
|
||||
(1024, [1], "Marketing")
|
||||
]
|
||||
|
||||
// Development view: fixed sizes acceptable
|
||||
private let previewSize: CGFloat = 200
|
||||
@ -46,7 +57,7 @@ public struct IconGeneratorView: View {
|
||||
// Generate button
|
||||
Button {
|
||||
Task {
|
||||
await generateIcon()
|
||||
await generateIcons()
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
@ -54,7 +65,7 @@ public struct IconGeneratorView: View {
|
||||
ProgressView()
|
||||
.tint(.white)
|
||||
}
|
||||
Text(isGenerating ? "Generating..." : "Generate & Save Icon")
|
||||
Text(isGenerating ? "Generating..." : "Generate & Save All Icons")
|
||||
}
|
||||
.font(.headline)
|
||||
.foregroundStyle(.white)
|
||||
@ -73,20 +84,31 @@ public struct IconGeneratorView: View {
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal)
|
||||
|
||||
// Generated icon confirmation
|
||||
if let icon = generatedIcon {
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundStyle(.green)
|
||||
Text(icon.filename)
|
||||
.font(.callout.monospaced())
|
||||
Spacer()
|
||||
Text("\(Int(icon.size))px")
|
||||
.font(.callout)
|
||||
.foregroundStyle(.secondary)
|
||||
// Generated icons list
|
||||
if !generatedIcons.isEmpty {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("Generated Files:")
|
||||
.font(.headline)
|
||||
.padding(.horizontal)
|
||||
|
||||
ForEach(generatedIcons) { icon in
|
||||
HStack {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.foregroundStyle(.green)
|
||||
Text(icon.filename)
|
||||
.font(.caption.monospaced())
|
||||
Spacer()
|
||||
Text("\(Int(icon.size))px")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 4)
|
||||
.background(Color.green.opacity(0.05))
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.background(Color.green.opacity(0.1))
|
||||
.padding(.vertical)
|
||||
.background(Color.green.opacity(0.05))
|
||||
.clipShape(.rect(cornerRadius: 12))
|
||||
.padding(.horizontal)
|
||||
}
|
||||
@ -108,16 +130,16 @@ public struct IconGeneratorView: View {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
instructionRow(number: 1, text: "Open Files app on your device/simulator")
|
||||
instructionRow(number: 2, text: "Navigate to: On My iPhone → \(appName)")
|
||||
instructionRow(number: 3, text: "Find AppIcon.png (1024×1024)")
|
||||
instructionRow(number: 3, text: "Find the generated PNG files")
|
||||
instructionRow(number: 4, text: "AirDrop or share to your Mac")
|
||||
instructionRow(number: 5, text: "Drag into Xcode's Assets.xcassets/AppIcon")
|
||||
}
|
||||
|
||||
Divider()
|
||||
|
||||
Text("Note: iOS uses a single 1024px icon")
|
||||
Text("Note: Multiple sizes generated")
|
||||
.font(.subheadline.bold())
|
||||
Text("Xcode automatically generates all required sizes from the 1024px source.")
|
||||
Text("While modern iOS can use a single 1024px icon, providing specific sizes ensures the best quality for notifications, settings, and spotlight.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
@ -138,35 +160,40 @@ public struct IconGeneratorView: View {
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func generateIcon() async {
|
||||
private func generateIcons() async {
|
||||
#if canImport(UIKit)
|
||||
isGenerating = true
|
||||
generatedIcon = nil
|
||||
status = "Generating icon..."
|
||||
generatedIcons = []
|
||||
status = "Generating icons..."
|
||||
|
||||
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
|
||||
|
||||
// Render the 1024px icon (the only size needed for modern iOS)
|
||||
let view = AppIconView(config: config, size: 1024)
|
||||
let renderer = ImageRenderer(content: view)
|
||||
renderer.scale = 1.0
|
||||
|
||||
if let uiImage = renderer.uiImage,
|
||||
let data = uiImage.pngData() {
|
||||
let filename = "AppIcon.png"
|
||||
let fileURL = documentsPath.appending(path: filename)
|
||||
|
||||
do {
|
||||
try data.write(to: fileURL)
|
||||
generatedIcon = GeneratedIconInfo(filename: filename, size: 1024)
|
||||
status = "✅ Icon saved to Documents folder!\nOpen Files app to find it."
|
||||
} catch {
|
||||
status = "Error saving icon: \(error.localizedDescription)"
|
||||
for iconDef in iconSizes {
|
||||
for scale in iconDef.scales {
|
||||
let pixelSize = iconDef.size * CGFloat(scale)
|
||||
let filename = scale == 1 ? "AppIcon-\(iconDef.size)px.png" : "AppIcon-\(iconDef.size)px@\(scale)x.png"
|
||||
|
||||
let view = AppIconView(config: config, size: pixelSize)
|
||||
let renderer = ImageRenderer(content: view)
|
||||
renderer.scale = 1.0 // We handle scale by pixel size
|
||||
|
||||
if let uiImage = renderer.uiImage,
|
||||
let data = uiImage.pngData() {
|
||||
let fileURL = documentsPath.appending(path: filename)
|
||||
|
||||
do {
|
||||
try data.write(to: fileURL)
|
||||
generatedIcons.append(GeneratedIconInfo(filename: filename, size: pixelSize))
|
||||
} catch {
|
||||
status = "Error saving \(filename): \(error.localizedDescription)"
|
||||
isGenerating = false
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = "⚠️ Failed to render icon"
|
||||
}
|
||||
|
||||
status = "✅ \(generatedIcons.count) icons saved to Documents folder!\nOpen Files app to find them."
|
||||
isGenerating = false
|
||||
#else
|
||||
status = "⚠️ Icon generation is only available on iOS"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user