Skip to content

Instantly share code, notes, and snippets.

@AdamWhitcroft
Created October 12, 2022 00:54
Show Gist options
  • Save AdamWhitcroft/0e1a57066ebd3f5c7547a680fd9f9ac6 to your computer and use it in GitHub Desktop.
Save AdamWhitcroft/0e1a57066ebd3f5c7547a680fd9f9ac6 to your computer and use it in GitHub Desktop.
//
// AppearanceSheet.swift
// PeePooBoobRelease
//
// Created by Adam Whitcroft on 2022-10-07.
//
import SwiftUI
struct AppearanceSheet: View {
// MARK: Dismiss
// Is this view visible or not
@Environment(\.dismiss) private var dismiss
@StateObject var viewModel = ChangeAppIconViewModel()
var body: some View {
ScrollView {
VStack(spacing: 16) {
// Section title
SectionTitleView(title: "App icon")
// App icon selector
InsetContentCard {
ForEach(ChangeAppIconViewModel.AppIcon.allCases) { appIcon in
HStack(spacing: 16) {
Image(uiImage: appIcon.preview)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60)
.cornerRadius(12)
Text(appIcon.description)
}
.onTapGesture {
withAnimation {
viewModel.updateAppIcon(to: appIcon)
}
}
}
}
}
.padding()
}
.navigationTitle("")
.navigationBarTitleDisplayMode(.inline)
.navigationBarBackButtonHidden(true)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
dismiss()
} label: {}
.buttonStyle(RoundButtonStyleSmall(iconName: "chevron.left", iconColor: .secondary))
}
ToolbarItem(placement: .principal) {
Text(Strings.SheetTitleAppearance)
.font(.system(.body, design: .rounded).weight(.bold))
}
}
}
}
enum AppIcon: String, CaseIterable, Identifiable {
case primary = "AppIcon"
case primaryInverted = "AppIcon-Inverted"
case red = "AppIcon-Red"
case redInverted = "AppIcon-Red-Inverted"
// etc...
var id: String { rawValue }
var iconName: String? {
switch self {
case .primary:
// `nil` resets back to the primary `AppIcon` icon
return nil
default:
return rawValue
}
}
var description: String {
switch self {
case .primary:
return "Default"
case .primaryInverted:
return "Something about primary inverted here..."
case .red:
return "Something about red here..."
case .redInverted:
return "Something about red inverted here..."
}
}
var preview: UIImage {
UIImage(named: rawValue + "-Preview") ?? UIImage()
}
}
final class ChangeAppIconViewModel: ObservableObject {
@Published private(set) var selectedAppIcon: AppIcon
init() {
if let iconName = UIApplication.shared.alternateIconName, let appIcon = AppIcon(rawValue: iconName) {
selectedAppIcon = appIcon
} else {
selectedAppIcon = .primary
}
}
func updateAppIcon(to icon: AppIcon) {
let previousAppIcon = selectedAppIcon
selectedAppIcon = icon
Task { @MainActor in
guard UIApplication.shared.alternateIconName != icon.iconName else {
// No need to update since we're already using this icon.
return
}
do {
try await UIApplication.shared.setAlternateIconName(icon.iconName)
} catch {
// We're only logging the error here and not actively handling the app icon failure
// since it's very unlikely to fail.
print("Updating icon to \(String(describing: icon.iconName)) failed.")
// Restore previous app icon
selectedAppIcon = previousAppIcon
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment