diff --git a/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png b/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png deleted file mode 100644 index 878f954..0000000 Binary files a/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png and /dev/null differ diff --git a/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/AppIcon.png b/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/AppIcon.png new file mode 100644 index 0000000..8c44447 Binary files /dev/null and b/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/AppIcon.png differ diff --git a/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/Contents.json b/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/Contents.json index a0146d3..ce8e776 100644 --- a/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Baccarat/Baccarat/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "AppIcon-1024.png", + "filename" : "AppIcon.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/Baccarat/Baccarat/Resources/Localizable.xcstrings b/Baccarat/Baccarat/Resources/Localizable.xcstrings index 51a7ffd..39b353e 100644 --- a/Baccarat/Baccarat/Resources/Localizable.xcstrings +++ b/Baccarat/Baccarat/Resources/Localizable.xcstrings @@ -117,6 +117,7 @@ }, "%lld." : { "comment" : "A numbered list item with a callout number and accompanying text. The first argument is the number of the item. The second argument is the text of the item.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -140,6 +141,7 @@ }, "%lldpx" : { "comment" : "A text label displaying the size of the app icon. The argument is the size of the icon in pixels.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -186,6 +188,7 @@ }, "• Add to Assets.xcassets/AppIcon" : { "comment" : "A step in the process of exporting app icons.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -208,6 +211,7 @@ } }, "• Call IconRenderer.renderAppIcon(config: .baccarat)" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -230,6 +234,7 @@ } }, "• Run the preview in Xcode" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -253,6 +258,7 @@ }, "• Save the resulting UIImage to files" : { "comment" : "A step in the process of exporting app icons.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -276,6 +282,7 @@ }, "• Screenshot the 1024px icon" : { "comment" : "A step in the process of exporting app icons, describing how to take a screenshot of a 1024px icon.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -299,6 +306,7 @@ }, "• Use an online tool to generate all sizes" : { "comment" : "A bullet point in the \"How to Export Icons\" section, describing how to use an online tool to generate all sizes for an app icon.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -528,6 +536,7 @@ }, "After generating:" : { "comment" : "A heading for the instructions section of the icon generator view.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -551,6 +560,7 @@ }, "All Sizes" : { "comment" : "A heading that describes the various sizes of the app icon.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -597,6 +607,7 @@ }, "Alternative: Use an online tool" : { "comment" : "A section header that suggests using an online tool to generate app icon sizes.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -666,6 +677,7 @@ }, "App Icon" : { "comment" : "A label displayed above the preview of the app icon.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -689,6 +701,7 @@ }, "App Icon Preview" : { "comment" : "A header describing the preview of the app icon.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -1240,6 +1253,7 @@ }, "Blackjack" : { "comment" : "The name of a blackjack game.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -1994,6 +2008,7 @@ }, "Generate & Save Icons" : { "comment" : "A button label that triggers the generation of app icons.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2017,6 +2032,7 @@ }, "Generated Icons:" : { "comment" : "A label displayed above the list of generated icon filenames.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2040,6 +2056,7 @@ }, "Generating..." : { "comment" : "A text that appears while generating icons.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2247,6 +2264,7 @@ }, "How to Export Icons" : { "comment" : "A section header explaining how to export app icons.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2337,6 +2355,7 @@ }, "Icon" : { "comment" : "The title for the tab that displays the app icon preview.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2360,6 +2379,7 @@ }, "Icon Generator" : { "comment" : "The title of the Icon Generator view.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2520,6 +2540,7 @@ }, "Launch" : { "comment" : "A tab label for the launch screen preview.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2929,6 +2950,7 @@ }, "Option 1: Screenshot from Preview" : { "comment" : "A description of one method for exporting app icons.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2952,6 +2974,7 @@ }, "Option 2: Use IconRenderer in Code" : { "comment" : "A description of how to use the `IconRenderer` in code to generate app icons.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2975,6 +2998,7 @@ }, "Other Game Icons" : { "comment" : "A label displayed above a section of the BrandingPreviewView", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -2998,6 +3022,7 @@ }, "Others" : { "comment" : "The tab label for the section that previews branding assets for other games.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -3411,6 +3436,7 @@ }, "Poker" : { "comment" : "The name of a poker game.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -3640,6 +3666,7 @@ }, "Roulette" : { "comment" : "The name of a roulette game.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -4326,6 +4353,7 @@ }, "These show how the same pattern works for other games" : { "comment" : "A description below the section of the view that previews icons for other games.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -4691,6 +4719,7 @@ }, "Upload the 1024px icon to appicon.co or makeappicon.com to generate all sizes automatically." : { "comment" : "A description of an alternative method for generating app icons.", + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { diff --git a/Baccarat/Baccarat/Views/Sheets/SettingsView.swift b/Baccarat/Baccarat/Views/Sheets/SettingsView.swift index a3659c0..4281ea3 100644 --- a/Baccarat/Baccarat/Views/Sheets/SettingsView.swift +++ b/Baccarat/Baccarat/Views/Sheets/SettingsView.swift @@ -350,6 +350,19 @@ struct SettingsView: View { .padding(.horizontal) .padding(.top, Design.Spacing.xSmall) + // ───────────────────────────────────────────────────────────── + // DEBUG SECTION - Only visible in DEBUG builds + // ───────────────────────────────────────────────────────────── + #if DEBUG + SheetSection(title: "DEBUG", icon: "ant.fill") { + BrandingDebugRows( + iconConfig: .baccarat, + launchConfig: .baccarat, + appName: "Baccarat" + ) + } + #endif + // 11. App Version Text(appVersionString) .font(.system(size: Design.BaseFontSize.callout)) diff --git a/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png b/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png deleted file mode 100644 index 86801ee..0000000 Binary files a/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/AppIcon-1024.png and /dev/null differ diff --git a/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/AppIcon.png b/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/AppIcon.png new file mode 100644 index 0000000..eecff4c Binary files /dev/null and b/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/AppIcon.png differ diff --git a/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/Contents.json b/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/Contents.json index a0146d3..ce8e776 100644 --- a/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/Blackjack/Blackjack/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "AppIcon-1024.png", + "filename" : "AppIcon.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/Blackjack/Blackjack/Resources/Localizable.xcstrings b/Blackjack/Blackjack/Resources/Localizable.xcstrings index 53fb547..10bee1f 100644 --- a/Blackjack/Blackjack/Resources/Localizable.xcstrings +++ b/Blackjack/Blackjack/Resources/Localizable.xcstrings @@ -119,6 +119,7 @@ }, "%lld." : { "comment" : "A numbered list item with a callout number and accompanying text. The first argument is the number of the item. The second argument is the text of the item.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -143,6 +144,7 @@ }, "%lldpx" : { "comment" : "A text label displaying the size of the app icon. The argument is the size of the icon in pixels.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -191,6 +193,7 @@ }, "• Add to Assets.xcassets/AppIcon" : { "comment" : "A bullet point describing how to add an app icon to Xcode's asset catalog.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -215,6 +218,7 @@ }, "• Call IconRenderer.renderAppIcon(config: .blackjack)" : { "comment" : "A bullet point in the \"Option 2: Use IconRenderer in Code\" section of the BrandingPreviewView.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -238,6 +242,7 @@ } }, "• Run the preview in Xcode" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -261,6 +266,7 @@ }, "• Save the resulting UIImage to files" : { "comment" : "A step in the process of exporting app icons.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -284,6 +290,7 @@ } }, "• Screenshot the 1024px icon" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -307,6 +314,7 @@ }, "• Use an online tool to generate all sizes" : { "comment" : "A step in the process of exporting app icons.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -828,6 +836,7 @@ }, "After generating:" : { "comment" : "A heading for instructions on how to use the IconGeneratorView.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -852,6 +861,7 @@ }, "All Sizes" : { "comment" : "A heading that describes the various sizes of the app icon.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -943,6 +953,7 @@ }, "Alternative: Use an online tool" : { "comment" : "A section header that suggests using an online tool to generate app icons.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -1013,6 +1024,7 @@ }, "App Icon" : { "comment" : "A label displayed above the preview of the app icon.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -1037,6 +1049,7 @@ }, "App Icon Preview" : { "comment" : "A title for the preview of the app icon.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -1105,6 +1118,7 @@ }, "Baccarat" : { "comment" : "The name of a casino game.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -2385,9 +2399,6 @@ } } } - }, - "Deal Splittable Pair (8s)" : { - }, "DEALER" : { "localizations" : { @@ -3589,6 +3600,7 @@ }, "Generate & Save Icons" : { "comment" : "A button label that triggers icon generation and saving.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -3613,6 +3625,7 @@ }, "Generated Icons:" : { "comment" : "A label describing the list of icons that have been successfully generated.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -3637,6 +3650,7 @@ }, "Generating..." : { "comment" : "A label indicating that the app is currently generating icons.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -3955,6 +3969,7 @@ }, "How to Export Icons" : { "comment" : "A section header explaining how to export app icons.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -4045,6 +4060,7 @@ }, "Icon" : { "comment" : "The label for the tab item representing the app icon preview.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -4069,6 +4085,7 @@ }, "Icon Generator" : { "comment" : "The title of the Icon Generator view.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -4434,6 +4451,7 @@ }, "Launch" : { "comment" : "A tab in the BrandingPreviewView that links to the launch screen preview.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -5093,6 +5111,7 @@ }, "Option 1: Screenshot from Preview" : { "comment" : "A description of one method for exporting app icons.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -5117,6 +5136,7 @@ }, "Option 2: Use IconRenderer in Code" : { "comment" : "A subheading within the instructions section of the BrandingPreviewView.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -5163,6 +5183,7 @@ }, "Other Game Icons" : { "comment" : "A label displayed above a section of the BrandingPreviewView that shows icons for other games.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -5187,6 +5208,7 @@ }, "Others" : { "comment" : "A tab label for the section displaying icons for other games.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -5464,6 +5486,7 @@ } }, "Poker" : { + "extractionState" : "stale", "localizations" : { "en" : { "stringUnit" : { @@ -5781,6 +5804,7 @@ }, "Roulette" : { "comment" : "The name of a roulette card.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -7195,6 +7219,7 @@ }, "These show how the same pattern works for other games" : { "comment" : "A description below the section of the view that previews icons for other games.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { @@ -7471,6 +7496,7 @@ }, "Upload the 1024px icon to appicon.co or makeappicon.com to generate all sizes automatically." : { "comment" : "A description of an alternative method for generating app icons.", + "extractionState" : "stale", "isCommentAutoGenerated" : true, "localizations" : { "en" : { diff --git a/Blackjack/Blackjack/Views/Sheets/SettingsView.swift b/Blackjack/Blackjack/Views/Sheets/SettingsView.swift index 12b19fc..0a0c120 100644 --- a/Blackjack/Blackjack/Views/Sheets/SettingsView.swift +++ b/Blackjack/Blackjack/Views/Sheets/SettingsView.swift @@ -435,28 +435,27 @@ struct SettingsView: View { // calls the corresponding debug function in GameState. // ───────────────────────────────────────────────────────────── #if DEBUG - if let state = gameState { - SheetSection(title: "DEBUG", icon: "ant.fill") { + SheetSection(title: "DEBUG", icon: "ant.fill") { + // Game-specific debug actions + if let state = gameState { // Split Testing - deals a pair of 8s - Button { + DebugActionRow( + title: "Deal Splittable Pair (8s)", + icon: "rectangle.split.2x1" + ) { triggerDebugDeal(state: state) - } label: { - HStack { - Text("Deal Splittable Pair (8s)") - .font(.system(size: Design.BaseFontSize.body, weight: .medium)) - .foregroundStyle(.orange) - Spacer() - Image(systemName: "rectangle.split.2x1") - .font(.system(size: Design.BaseFontSize.large)) - .foregroundStyle(.orange) - } - .frame(minHeight: CasinoDesign.Size.actionRowMinHeight) } - // Add new debug buttons here: - // Divider().background(Color.orange.opacity(Design.Opacity.hint)) - // Button { triggerDebugBlackjack(state: state) } label: { ... } + Divider() + .background(Color.orange.opacity(Design.Opacity.hint)) } + + // Branding tools (from CasinoKit) + BrandingDebugRows( + iconConfig: .blackjack, + launchConfig: .blackjack, + appName: "Blackjack" + ) } #endif diff --git a/CasinoKit/Sources/CasinoKit/Exports.swift b/CasinoKit/Sources/CasinoKit/Exports.swift index 94a6c23..8973866 100644 --- a/CasinoKit/Sources/CasinoKit/Exports.swift +++ b/CasinoKit/Sources/CasinoKit/Exports.swift @@ -72,6 +72,9 @@ // - SelectableRow (card-like selectable picker row) // - SelectionIndicator (checkmark circle) // - BadgePill (capsule badge for values) +// - DebugNavigationRow (debug row with navigation) +// - DebugActionRow (debug row with action) +// - BrandingDebugRows (icon generator + branding preview rows) // MARK: - Branding diff --git a/CasinoKit/Sources/CasinoKit/Resources/Localizable.xcstrings b/CasinoKit/Sources/CasinoKit/Resources/Localizable.xcstrings index 82f145e..5a9f60d 100644 --- a/CasinoKit/Sources/CasinoKit/Resources/Localizable.xcstrings +++ b/CasinoKit/Sources/CasinoKit/Resources/Localizable.xcstrings @@ -93,6 +93,10 @@ } } }, + "%lld." : { + "comment" : "A numbered list item with a callout number and accompanying text. The first argument is the number of the item. The second argument is the text describing the item.", + "isCommentAutoGenerated" : true + }, "%lld%%" : { "comment" : "A text displaying the current volume percentage. The argument is a value between 0.0 (no volume) and 1.0 (full volume).", "isCommentAutoGenerated" : true, @@ -141,6 +145,10 @@ } } }, + "%lldpx" : { + "comment" : "A text label displaying the size of an app icon. The argument is the size of the icon in pixels.", + "isCommentAutoGenerated" : true + }, "•" : { "comment" : "A bullet point indicator.", "isCommentAutoGenerated" : true, @@ -316,6 +324,10 @@ } } }, + "1024 × 1024px" : { + "comment" : "A description of the size of the app icon.", + "isCommentAutoGenerated" : true + }, "Ace" : { "localizations" : { "en" : { @@ -365,6 +377,10 @@ } } }, + "After generating:" : { + "comment" : "A heading describing the steps to take after generating app icons.", + "isCommentAutoGenerated" : true + }, "All game data is stored:" : { "localizations" : { "en" : { @@ -387,6 +403,10 @@ } } }, + "App Icon" : { + "comment" : "The title of the section displaying the app icon preview.", + "isCommentAutoGenerated" : true + }, "App Icon Preview" : { "comment" : "A title for the preview section of the icon export view.", "isCommentAutoGenerated" : true, @@ -1099,6 +1119,14 @@ } } }, + "Generate & Save Icon" : { + "comment" : "A button label that triggers icon generation and saving.", + "isCommentAutoGenerated" : true + }, + "Generating..." : { + "comment" : "A button label indicating that the app is currently generating icons.", + "isCommentAutoGenerated" : true + }, "Global" : { "comment" : "Title for the \"Global\" tab in the statistics view.", "isCommentAutoGenerated" : true @@ -1202,6 +1230,14 @@ } } }, + "Icon" : { + "comment" : "The label for the tab that displays the app icon preview.", + "isCommentAutoGenerated" : true + }, + "Icon Generator" : { + "comment" : "The title of the icon generator view.", + "isCommentAutoGenerated" : true + }, "If you choose to enable iCloud sync:" : { "localizations" : { "en" : { @@ -1400,6 +1436,10 @@ } } }, + "Launch" : { + "comment" : "A tab label for the launch screen preview.", + "isCommentAutoGenerated" : true + }, "Locally on your device using iOS standard storage" : { "localizations" : { "en" : { @@ -1578,6 +1618,10 @@ }, "No Session History" : { + }, + "Note: iOS uses a single 1024px icon" : { + "comment" : "A note explaining that iOS uses a single 1024px icon.", + "isCommentAutoGenerated" : true }, "Our apps do not integrate with third-party services that collect user data. We do not share any information with third parties." : { "localizations" : { @@ -2106,6 +2150,10 @@ } } }, + "To Export" : { + "comment" : "A section header explaining how to export branding assets.", + "isCommentAutoGenerated" : true + }, "TOTAL" : { "comment" : "A label displayed alongside the total winnings in the result banner.", "isCommentAutoGenerated" : true @@ -2148,6 +2196,10 @@ } } }, + "Use the Icon Generator in Settings → DEBUG to save the 1024px icon to the Files app, then add it to Xcode's Assets.xcassets/AppIcon." : { + "comment" : "Instructions for exporting an app icon.", + "isCommentAutoGenerated" : true + }, "VIP" : { "localizations" : { "en" : { @@ -2344,6 +2396,10 @@ "comment" : "A label for the worst session amount in the statistics view.", "isCommentAutoGenerated" : true }, + "Xcode automatically generates all required sizes from the 1024px source." : { + "comment" : "A footnote explaining that Xcode generates all app icon sizes from the 1024px source image.", + "isCommentAutoGenerated" : true + }, "You can disable iCloud sync at any time in the app settings" : { "comment" : "Text in the Privacy Policy View explaining how to disable iCloud sync in the app settings.", "isCommentAutoGenerated" : true, diff --git a/CasinoKit/Sources/CasinoKit/Views/Branding/AppIconView.swift b/CasinoKit/Sources/CasinoKit/Views/Branding/AppIconView.swift index 045dd90..aee2997 100644 --- a/CasinoKit/Sources/CasinoKit/Views/Branding/AppIconView.swift +++ b/CasinoKit/Sources/CasinoKit/Views/Branding/AppIconView.swift @@ -57,14 +57,27 @@ public struct AppIconView: View { self.size = size } - // iOS clips app icons with a superellipse mask. Inset decorative elements - // to prevent clipping. The inset is approximately 4% of the icon size. - private var borderInset: CGFloat { size * 0.04 } - private var insetCornerRadius: CGFloat { (size - borderInset * 2) * 0.18 } + // Size calculations private var iconSize: CGFloat { size * 0.35 } - private var titleSize: CGFloat { size * 0.12 } private var subtitleSize: CGFloat { size * 0.25 } - private var borderWidth: CGFloat { size * 0.015 } + + /// Dynamic title size based on text length. + /// Shorter titles get larger fonts, longer titles shrink to fit within the border. + private var titleSize: CGFloat { + let baseSize = size * 0.12 + let length = config.title.count + + // Scale factor: full size for ≤6 chars, progressively smaller for longer + let scaleFactor: CGFloat = switch length { + case ...6: 1.0 // "CASINO", "POKER" + case 7: 0.95 // + case 8: 0.85 // "BACCARAT" + case 9: 0.75 // "BLACKJACK" + default: 0.65 // Very long titles + } + + return baseSize * scaleFactor + } public var body: some View { ZStack { @@ -83,22 +96,6 @@ public struct AppIconView: View { DiamondPatternOverlay(size: size) .opacity(0.08) - // Decorative border - inset to avoid iOS mask clipping - RoundedRectangle(cornerRadius: insetCornerRadius) - .strokeBorder( - LinearGradient( - colors: [ - config.accentColor, - config.accentColor.opacity(0.6), - config.accentColor - ], - startPoint: .topLeading, - endPoint: .bottomTrailing - ), - lineWidth: borderWidth - ) - .padding(borderInset) - // Content VStack(spacing: size * 0.03) { // Icon symbol @@ -187,6 +184,38 @@ private struct DiamondPatternOverlay: View { .background(Color.gray) } +#Preview("Title Scaling") { + let shortTitle = AppIconConfig(title: "POKER", iconSymbol: "suit.diamond.fill") + let mediumTitle = AppIconConfig(title: "BACCARAT", iconSymbol: "suit.spade.fill") + let longTitle = AppIconConfig( + title: "BLACKJACK", + subtitle: "21", + iconSymbol: "suit.club.fill", + primaryColor: Color(red: 0.05, green: 0.35, blue: 0.15), + secondaryColor: Color(red: 0.03, green: 0.2, blue: 0.1) + ) + + return HStack(spacing: 20) { + VStack { + AppIconView(config: shortTitle, size: 180) + .clipShape(.rect(cornerRadius: 180 * 0.22)) + Text("6 chars").font(.caption) + } + VStack { + AppIconView(config: mediumTitle, size: 180) + .clipShape(.rect(cornerRadius: 180 * 0.22)) + Text("8 chars").font(.caption) + } + VStack { + AppIconView(config: longTitle, size: 180) + .clipShape(.rect(cornerRadius: 180 * 0.22)) + Text("9 chars").font(.caption) + } + } + .padding() + .background(Color.gray) +} + #Preview("All Sizes") { LazyVGrid(columns: [GridItem(.adaptive(minimum: 100))], spacing: 20) { ForEach([180, 120, 87, 60, 40], id: \.self) { size in diff --git a/CasinoKit/Sources/CasinoKit/Views/Branding/BrandingPreviewView.swift b/CasinoKit/Sources/CasinoKit/Views/Branding/BrandingPreviewView.swift index a0e3074..96265dd 100644 --- a/CasinoKit/Sources/CasinoKit/Views/Branding/BrandingPreviewView.swift +++ b/CasinoKit/Sources/CasinoKit/Views/Branding/BrandingPreviewView.swift @@ -9,18 +9,14 @@ import SwiftUI /// Preview view for app branding assets. -/// Use this during development to preview and export icons. +/// Use this during development to preview icons and launch screens. public struct BrandingPreviewView: View { let iconConfig: AppIconConfig let launchConfig: LaunchScreenConfig let appName: String - /// Other game configs for comparison preview. - let otherGames: [(name: String, config: AppIconConfig)] - // Development view: fixed sizes acceptable private let largePreviewSize: CGFloat = 300 - private let comparisonIconSize: CGFloat = 150 private let iconCornerRadiusRatio: CGFloat = 0.22 /// Creates a branding preview view. @@ -28,17 +24,14 @@ public struct BrandingPreviewView: View { /// - iconConfig: The app icon configuration for this game. /// - launchConfig: The launch screen configuration for this game. /// - appName: The app name for display purposes. - /// - otherGames: Other game configs for side-by-side comparison (optional). public init( iconConfig: AppIconConfig, launchConfig: LaunchScreenConfig, - appName: String, - otherGames: [(name: String, config: AppIconConfig)] = [] + appName: String ) { self.iconConfig = iconConfig self.launchConfig = launchConfig self.appName = appName - self.otherGames = otherGames } public var body: some View { @@ -53,20 +46,9 @@ public struct BrandingPreviewView: View { .clipShape(.rect(cornerRadius: largePreviewSize * iconCornerRadiusRatio)) .shadow(radius: 20) - Text("All Sizes") - .font(.title2.bold()) - - LazyVGrid(columns: [GridItem(.adaptive(minimum: 100))], spacing: 20) { - ForEach([180, 120, 87, 60, 40], id: \.self) { size in - VStack { - AppIconView(config: iconConfig, size: CGFloat(size)) - .clipShape(.rect(cornerRadius: CGFloat(size) * iconCornerRadiusRatio)) - Text("\(size)px") - .font(.caption) - .foregroundStyle(.secondary) - } - } - } + Text("1024 × 1024px") + .font(.caption) + .foregroundStyle(.secondary) instructionsSection } @@ -81,60 +63,17 @@ public struct BrandingPreviewView: View { .tabItem { Label("Launch", systemImage: "rectangle.portrait.fill") } - - // Other Games Preview (if provided) - if !otherGames.isEmpty { - ScrollView { - VStack(spacing: 32) { - Text("Other Game Icons") - .font(.largeTitle.bold()) - - LazyVGrid(columns: [GridItem(.adaptive(minimum: 160))], spacing: 20) { - ForEach(otherGames, id: \.name) { game in - VStack { - AppIconView(config: game.config, size: comparisonIconSize) - .clipShape(.rect(cornerRadius: comparisonIconSize * iconCornerRadiusRatio)) - Text(game.name) - .font(.caption) - } - } - } - - Text("These show how the same pattern works for other games") - .font(.callout) - .foregroundStyle(.secondary) - } - .padding() - } - .tabItem { - Label("Others", systemImage: "square.grid.2x2") - } - } } } private var instructionsSection: some View { VStack(alignment: .leading, spacing: 12) { - Text("How to Export Icons") + Text("To Export") .font(.headline) - VStack(alignment: .leading, spacing: 8) { - Text("Option 1: Screenshot from Preview") - .font(.subheadline.bold()) - Text("• Run the preview in Xcode") - Text("• Screenshot the 1024px icon") - Text("• Use an online tool to generate all sizes") - } - - VStack(alignment: .leading, spacing: 8) { - Text("Option 2: Use IconRenderer in Code") - .font(.subheadline.bold()) - Text("• Call IconRenderer.renderAppIcon(config: .\(appName.lowercased()))") - Text("• Save the resulting UIImage to files") - Text("• Add to Assets.xcassets/AppIcon") - } + Text("Use the Icon Generator in Settings → DEBUG to save the 1024px icon to the Files app, then add it to Xcode's Assets.xcassets/AppIcon.") + .font(.callout) } - .font(.callout) .foregroundStyle(.secondary) .frame(maxWidth: .infinity, alignment: .leading) .padding() diff --git a/CasinoKit/Sources/CasinoKit/Views/Branding/IconGeneratorView.swift b/CasinoKit/Sources/CasinoKit/Views/Branding/IconGeneratorView.swift index cd575c2..9915aef 100644 --- a/CasinoKit/Sources/CasinoKit/Views/Branding/IconGeneratorView.swift +++ b/CasinoKit/Sources/CasinoKit/Views/Branding/IconGeneratorView.swift @@ -14,9 +14,9 @@ public struct IconGeneratorView: View { let config: AppIconConfig let appName: String - @State private var status: String = "Tap the button to generate icons" + @State private var status: String = "Tap the button to generate the icon" @State private var isGenerating = false - @State private var generatedIcons: [GeneratedIconInfo] = [] + @State private var generatedIcon: GeneratedIconInfo? // Development view: fixed sizes acceptable private let previewSize: CGFloat = 200 @@ -46,7 +46,7 @@ public struct IconGeneratorView: View { // Generate button Button { Task { - await generateIcons() + await generateIcon() } } label: { HStack { @@ -54,7 +54,7 @@ public struct IconGeneratorView: View { ProgressView() .tint(.white) } - Text(isGenerating ? "Generating..." : "Generate & Save Icons") + Text(isGenerating ? "Generating..." : "Generate & Save Icon") } .font(.headline) .foregroundStyle(.white) @@ -73,24 +73,17 @@ public struct IconGeneratorView: View { .multilineTextAlignment(.center) .padding(.horizontal) - // Generated icons - if !generatedIcons.isEmpty { - VStack(alignment: .leading, spacing: 12) { - Text("Generated Icons:") - .font(.headline) - - 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) - } - } + // 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) } .padding() .background(Color.green.opacity(0.1)) @@ -115,16 +108,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 the AppIcon-1024.png file") + instructionRow(number: 3, text: "Find AppIcon.png (1024×1024)") instructionRow(number: 4, text: "AirDrop or share to your Mac") instructionRow(number: 5, text: "Drag into Xcode's Assets.xcassets/AppIcon") } Divider() - Text("Alternative: Use an online tool") + Text("Note: iOS uses a single 1024px icon") .font(.subheadline.bold()) - Text("Upload the 1024px icon to appicon.co or makeappicon.com to generate all sizes automatically.") + Text("Xcode automatically generates all required sizes from the 1024px source.") .font(.caption) .foregroundStyle(.secondary) } @@ -145,50 +138,32 @@ public struct IconGeneratorView: View { } @MainActor - private func generateIcons() async { + private func generateIcon() async { isGenerating = true - generatedIcons = [] - status = "Generating icons..." - - let sizes: [(CGFloat, String)] = [ - (1024, "AppIcon-1024"), - (180, "AppIcon-180"), - (120, "AppIcon-120"), - (87, "AppIcon-87"), - (80, "AppIcon-80"), - (60, "AppIcon-60"), - (40, "AppIcon-40") - ] + generatedIcon = nil + status = "Generating icon..." let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] - for (size, name) in sizes { - // Render the icon - let view = AppIconView(config: config, size: size) - let renderer = ImageRenderer(content: view) - renderer.scale = 1.0 - - if let uiImage = renderer.uiImage, - let data = uiImage.pngData() { - let filename = "\(name).png" - let fileURL = documentsPath.appending(path: filename) - - do { - try data.write(to: fileURL) - generatedIcons.append(GeneratedIconInfo(filename: filename, size: size)) - } catch { - status = "Error saving \(filename): \(error.localizedDescription)" - } - } - - // Small delay for UI feedback - try? await Task.sleep(for: .milliseconds(100)) - } + // 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 generatedIcons.count == sizes.count { - status = "✅ All icons saved to Documents folder!\nOpen Files app to find them." + 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)" + } } else { - status = "⚠️ Some icons failed to generate" + status = "⚠️ Failed to render icon" } isGenerating = false diff --git a/CasinoKit/Sources/CasinoKit/Views/Settings/DebugSection.swift b/CasinoKit/Sources/CasinoKit/Views/Settings/DebugSection.swift new file mode 100644 index 0000000..c8262d4 --- /dev/null +++ b/CasinoKit/Sources/CasinoKit/Views/Settings/DebugSection.swift @@ -0,0 +1,130 @@ +// +// DebugSection.swift +// CasinoKit +// +// Reusable debug section for settings views. +// Only visible in DEBUG builds. +// + +import SwiftUI + +/// A debug row that navigates to a destination view. +public struct DebugNavigationRow: View { + let title: String + let icon: String + let destination: () -> Destination + + public init( + title: String, + icon: String, + @ViewBuilder destination: @escaping () -> Destination + ) { + self.title = title + self.icon = icon + self.destination = destination + } + + public var body: some View { + NavigationLink { + destination() + } label: { + HStack { + Text(title) + .font(.system(size: CasinoDesign.BaseFontSize.body, weight: .medium)) + .foregroundStyle(.orange) + Spacer() + Image(systemName: icon) + .font(.system(size: CasinoDesign.BaseFontSize.large)) + .foregroundStyle(.orange) + } + .frame(minHeight: CasinoDesign.Size.actionRowMinHeight) + } + } +} + +/// A debug row that performs an action. +public struct DebugActionRow: View { + let title: String + let icon: String + let action: () -> Void + + public init( + title: String, + icon: String, + action: @escaping () -> Void + ) { + self.title = title + self.icon = icon + self.action = action + } + + public var body: some View { + Button(action: action) { + HStack { + Text(title) + .font(.system(size: CasinoDesign.BaseFontSize.body, weight: .medium)) + .foregroundStyle(.orange) + Spacer() + Image(systemName: icon) + .font(.system(size: CasinoDesign.BaseFontSize.large)) + .foregroundStyle(.orange) + } + .frame(minHeight: CasinoDesign.Size.actionRowMinHeight) + } + } +} + +/// Branding debug rows for icon generation and preview. +/// Use these in your app's debug section. +public struct BrandingDebugRows: View { + let iconConfig: AppIconConfig + let launchConfig: LaunchScreenConfig + let appName: String + + public init( + iconConfig: AppIconConfig, + launchConfig: LaunchScreenConfig, + appName: String + ) { + self.iconConfig = iconConfig + self.launchConfig = launchConfig + self.appName = appName + } + + public var body: some View { + DebugNavigationRow( + title: "Icon Generator", + icon: "app.badge.fill" + ) { + IconGeneratorView(config: iconConfig, appName: appName) + } + + Divider() + .background(Color.orange.opacity(0.3)) + + DebugNavigationRow( + title: "Branding Preview", + icon: "paintpalette.fill" + ) { + BrandingPreviewView( + iconConfig: iconConfig, + launchConfig: launchConfig, + appName: appName + ) + } + } +} + +#Preview { + NavigationStack { + List { + Section("Debug") { + BrandingDebugRows( + iconConfig: .example, + launchConfig: .example, + appName: "Casino" + ) + } + } + } +}