import SwiftUI
struct LogoView: View {
@Environment(\.dismiss) private var dismiss
@State private var selectedIcon = UIApplication.shared.alternateIconName ?? "AppIcon"
@State private var showPricing: Bool = false
// Toggle this from your entitlement system
let hasPro: Bool = SubscriptionManager.shared.isPremium
var body: some View {
GeometryReader { geo in
VStack(spacing: 24) {
Capsule()
.fill(Color.secondary.opacity(0.4))
.frame(width: 40, height: 5)
.padding(.top, 8)
// MARK: - Free Icons
SectionHeader(
title: "App Icons",
subtitle: "Available to all users"
)
VStack(spacing: 16) {
IconRow(
imageName: "IconLogo",
title: "Default",
iconName: "AppIcon",
width: geo.size.width * 0.9,
selectedIcon: $selectedIcon,
isLocked: false
)
IconRow(
imageName: "MessagesLogo",
title: "Messages",
iconName: "Messages",
width: geo.size.width * 0.9,
selectedIcon: $selectedIcon,
isLocked: false
)
}
// MARK: - Pro Icons
SectionHeader(
title: "Pro Icons",
subtitle: "Unlock with Pro"
)
VStack(spacing: 16) {
IconRow(
imageName: "SnapchatLogo",
title: "Snapchat",
iconName: "Snapchat",
width: geo.size.width * 0.9,
selectedIcon: $selectedIcon,
isLocked: !hasPro
)
IconRow(
imageName: "InstagramLogo",
title: "Instagram",
iconName: "Instagram",
width: geo.size.width * 0.9,
selectedIcon: $selectedIcon,
isLocked: !hasPro
)
}
.opacity(hasPro ? 1 : 0.45)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(.systemGroupedBackground))
}
.presentationDetents([.medium, .large])
.presentationDragIndicator(.hidden)
.sheet(isPresented: $showPricing) {
PricingView()
}
}
}
struct IconRow: View {
let imageName: String
let title: String
let iconName: String
let width: CGFloat
@Binding var selectedIcon: String
var isLocked: Bool
var isSelected: Bool {
selectedIcon == iconName
}
var body: some View {
Button {
// If locked and not premium
if !SubscriptionManager.shared.isPremium && isLocked {
RedToast(message: "You need premium to unlock this feature")
HapticManager.shared.error()
return
}
// Determine the correct icon name to pass
let iconToSet: String? = (iconName == "AppIcon") ? nil : iconName
// Only attempt change if it’s different from current icon
if UIApplication.shared.supportsAlternateIcons,
UIApplication.shared.alternateIconName != iconToSet {
UIApplication.shared.setAlternateIconName(iconToSet) { error in
if let error = error {
print("Failed to change icon:", error.localizedDescription)
HapticManager.shared.error()
} else {
print("Icon change requested successfully")
HapticManager.shared.medium()
// Update selectedIcon on main thread
DispatchQueue.main.async {
selectedIcon = iconName
}
}
}
} else {
print("Icon already selected or alternate icons not supported")
}
} label: {
HStack(spacing: 16) {
Image(imageName)
.resizable()
.scaledToFit()
.frame(width: 64, height: 64)
.clipShape(RoundedRectangle(cornerRadius: 14))
.shadow(radius: 4)
Text(title)
.font(.headline)
Spacer()
if isLocked && !SubscriptionManager.shared.isPremium {
Image(systemName: "lock.fill")
.foregroundStyle(.secondary)
} else if selectedIcon == iconName {
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(.blue)
} else {
Image(systemName: "circle")
.foregroundStyle(.blue)
}
}
.padding()
.frame(width: width)
.background(
RoundedRectangle(cornerRadius: 20)
.fill(.background)
.shadow(color: .black.opacity(0.05), radius: 8, y: 4)
)
}
.buttonStyle(.plain)
}
}
struct SectionHeader: View {
let title: String
let subtitle: String
var body: some View {
VStack(alignment: .leading, spacing: 4) {
Text(title)
.font(.headline)
Text(subtitle)
.font(.footnote)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal)
}
}
a a a a. a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a. a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a. A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a. a a a a a a a a a a a a a a a a a a a
struct IconRow: View { let imageName: String let title: String let iconName: String let width: CGFloat
@Binding var selectedIcon: String
var isLocked: Bool
var isSelected: Bool { selectedIcon == iconName }
var body: some View { Button { // If locked and not premium if !SubscriptionManager.shared.isPremium && isLocked { RedToast(message: "You need premium to unlock this feature") HapticManager.shared.error() return }
// Determine the correct icon name to pass let iconToSet: String? = (iconName == "AppIcon") ? nil : iconName
// Only attempt change if it’s different from current icon if UIApplication.shared.supportsAlternateIcons, UIApplication.shared.alternateIconName != iconToSet {
UIApplication.shared.setAlternateIconName(iconToSet) { error in if let error = error { print("Failed to change icon:", error.localizedDescription) HapticManager.shared.error() } else { print("Icon change requested successfully") HapticManager.shared.medium() // Update selectedIcon on main thread DispatchQueue.main.async { selectedIcon = iconName } } }
} else { print("Icon already selected or alternate icons not supported") }
struct SectionHeader: View { let title: String let subtitle: String
var body: some View { VStack(alignment: .leading, spacing: 4) { Text(title) .font(.headline)
Text(subtitle) .font(.footnote) .foregroundStyle(.secondary) } .frame(maxWidth: .infinity, alignment: .leading) .padding(.horizontal) } } [/code] a a a a. a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a. a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a. A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a. a a a a a a a a a a a a a a a a a a a