diff --git a/AltStore/View Components/AppIconView.swift b/AltStore/View Components/AppIconView.swift index acec82d1..27a05d6b 100644 --- a/AltStore/View Components/AppIconView.swift +++ b/AltStore/View Components/AppIconView.swift @@ -10,23 +10,42 @@ import SwiftUI import AsyncImage struct AppIconView: View { + @ObservedObject private var iO = Inject.observer + @ObservedObject private var sideStoreIconData = AppIconsData.shared + let iconUrl: URL? + var isSideStore = false var size: CGFloat = 64 var cornerRadius: CGFloat { size * 0.234 } - var body: some View { - if let iconUrl { - AsyncImage(url: iconUrl) { image in - image + var image: some View { + if isSideStore { + return AnyView( + Image(uiImage: UIImage(named: sideStoreIconData.selectedIconName! + "-image") ?? UIImage()) .resizable() - } placeholder: { - Color(UIColor.secondarySystemBackground) - } + .renderingMode(.original) + ) + } + if let iconUrl { + return AnyView( + AsyncImage(url: iconUrl) { image in + image + .resizable() + } placeholder: { + Color(UIColor.secondarySystemBackground) + } + ) + } + return AnyView(Color(UIColor.secondarySystemBackground)) + } + + var body: some View { + image .frame(width: size, height: size) .clipShape(RoundedRectangle(cornerRadius: cornerRadius, style: .continuous)) - } + .enableInjection() } } diff --git a/AltStore/View Components/AppRowView.swift b/AltStore/View Components/AppRowView.swift index d49929eb..f9034f4e 100644 --- a/AltStore/View Components/AppRowView.swift +++ b/AltStore/View Components/AppRowView.swift @@ -20,7 +20,7 @@ struct AppRowView: View { var body: some View { HStack(alignment: .center, spacing: 12) { - AppIconView(iconUrl: storeApp?.iconURL) + AppIconView(iconUrl: storeApp?.iconURL, isSideStore: storeApp?.bundleIdentifier == Bundle.Info.appbundleIdentifier) VStack(alignment: .leading, spacing: 2) { Text(app.name) diff --git a/AltStore/Views/App Detail/AppDetailView.swift b/AltStore/Views/App Detail/AppDetailView.swift index 0347115d..a7f199a5 100644 --- a/AltStore/Views/App Detail/AppDetailView.swift +++ b/AltStore/Views/App Detail/AppDetailView.swift @@ -58,7 +58,7 @@ struct AppDetailView: View { ToolbarItemGroup(placement: .principal) { HStack { Spacer() - AppIconView(iconUrl: storeApp.iconURL, size: 24) + AppIconView(iconUrl: storeApp.iconURL, isSideStore: storeApp.bundleIdentifier == Bundle.Info.appbundleIdentifier, size: 24) Text(storeApp.name) .bold() Spacer() @@ -74,7 +74,7 @@ struct AppDetailView: View { var headerView: some View { ZStack(alignment: .center) { GeometryReader { proxy in - AppIconView(iconUrl: storeApp.iconURL, size: proxy.frame(in: .global).width) + AppIconView(iconUrl: storeApp.iconURL, isSideStore: storeApp.bundleIdentifier == Bundle.Info.appbundleIdentifier, size: proxy.frame(in: .global).width) .blur(radius: headerBlurRadius) .offset(y: min(0, scrollOffset)) } diff --git a/AltStore/Views/Settings/AppIconsView.swift b/AltStore/Views/Settings/AppIconsView.swift index 6d1829ca..fd4ef73c 100644 --- a/AltStore/Views/Settings/AppIconsView.swift +++ b/AltStore/Views/Settings/AppIconsView.swift @@ -9,7 +9,7 @@ import SwiftUI import SFSafeSymbols -private struct Icon: Identifiable { +struct Icon: Identifiable { var id: String { assetName } var displayName: String let assetName: String @@ -21,22 +21,18 @@ private struct SpecialIcon { let forceIndex: Int? } -struct AppIconsView: View { - private let specialIcons = [ +class AppIconsData: ObservableObject { + static let shared: AppIconsData = AppIconsData() + + private static let specialIcons = [ SpecialIcon(assetName: "Neon", suffix: "(Stable)", forceIndex: 0), SpecialIcon(assetName: "Starburst", suffix: "(Beta)", forceIndex: 1), SpecialIcon(assetName: "Steel", suffix: "(Nightly)", forceIndex: 2), ] - private let artists = [ - "Chris (LitRitt)": ["Neon", "Starburst", "Steel", "Storm"], - "naturecodevoid": ["Honeydew", "Midnight", "Sky"] - ] - private var icons: [Icon] = [] - private var primaryIcon: Icon - - @State private var selectedIcon: String? = "" // this is just so the list row background changes when selecting a value, I couldn't get it to keep the selected icon name (for some reason it was always "", even when I set it to the selected icon asset name) - @State private var selectedIconAssetName: String // FIXME: use selectedIcon instead + @Published var icons: [Icon] = [] + @Published var primaryIcon: Icon? + @Published var selectedIconName: String? init() { let bundleIcons = Bundle.main.object(forInfoDictionaryKey: "CFBundleIcons") as! [String: Any] @@ -44,7 +40,7 @@ struct AppIconsView: View { let primaryIconData = bundleIcons["CFBundlePrimaryIcon"] as! [String: Any] let primaryIconName = primaryIconData["CFBundleIconName"] as! String primaryIcon = Icon(displayName: primaryIconName, assetName: primaryIconName) - icons.append(primaryIcon) + icons.append(primaryIcon!) for (key, _) in bundleIcons["CFBundleAlternateIcons"] as! [String: Any] { icons.append(Icon(displayName: key, assetName: key)) @@ -53,7 +49,7 @@ struct AppIconsView: View { // sort alphabetically icons.sort { $0.assetName < $1.assetName } - for specialIcon in specialIcons { + for specialIcon in AppIconsData.specialIcons { guard let icon = icons.enumerated().first(where: { $0.element.assetName == specialIcon.assetName }) else { continue } if let suffix = specialIcon.suffix { @@ -67,18 +63,36 @@ struct AppIconsView: View { } if let alternateIconName = UIApplication.shared.alternateIconName { - selectedIconAssetName = icons.first { $0.assetName == alternateIconName }?.assetName ?? primaryIcon.assetName + selectedIconName = icons.first { $0.assetName == alternateIconName }?.assetName ?? primaryIcon!.assetName } else { - selectedIconAssetName = primaryIcon.assetName + selectedIconName = primaryIcon!.assetName } } +} + +struct AppIconsView: View { + @ObservedObject private var iO = Inject.observer + @ObservedObject private var data = AppIconsData.shared + + private let artists = [ + "Chris (LitRitt)": ["Neon", "Starburst", "Steel", "Storm"], + "naturecodevoid": ["Honeydew", "Midnight", "Sky"], + "Swifticul": ["Vista"], + ] + + @State private var selectedIcon: String? = "" // this is just so the list row background changes when selecting a value, I couldn't get it to keep the selected icon name (for some reason it was always "", even when I set it to the selected icon asset name) + + private let size: CGFloat = 72 + private var cornerRadius: CGFloat { + size * 0.234 + } var body: some View { - List(icons, selection: $selectedIcon) { icon in + List(data.icons, selection: $selectedIcon) { icon in SwiftUI.Button(action: { - selectedIconAssetName = icon.assetName + data.selectedIconName = icon.assetName // Pass nil for primary icon - UIApplication.shared.setAlternateIconName(icon.assetName == primaryIcon.assetName ? nil : icon.assetName, completionHandler: { error in + UIApplication.shared.setAlternateIconName(icon.assetName == data.primaryIcon!.assetName ? nil : icon.assetName, completionHandler: { error in if let error = error { print("error when setting alternate app icon to \(icon.assetName): \(error.localizedDescription)") } else { @@ -91,8 +105,8 @@ struct AppIconsView: View { Image(uiImage: UIImage(named: icon.assetName + "-image") ?? UIImage()) .resizable() .renderingMode(.original) - .cornerRadius(12.6) // https://stackoverflow.com/a/10239376 - .frame(width: 72, height: 72) + .cornerRadius(cornerRadius) + .frame(width: size, height: size) VStack(alignment: .leading) { Text(icon.displayName) if let artist = artists.first(where: { $0.value.contains(icon.assetName) }) { @@ -101,7 +115,7 @@ struct AppIconsView: View { } } Spacer() - if selectedIconAssetName == icon.assetName { + if data.selectedIconName == icon.assetName { Image(systemSymbol: .checkmark) .foregroundColor(Color.blue) } @@ -109,6 +123,7 @@ struct AppIconsView: View { }.foregroundColor(.primary) } .navigationTitle(L10n.AppIconsView.title) + .enableInjection() } } diff --git a/AltStore/Views/Settings/ErrorLogView.swift b/AltStore/Views/Settings/ErrorLogView.swift index 568a9e10..38c008d3 100644 --- a/AltStore/Views/Settings/ErrorLogView.swift +++ b/AltStore/Views/Settings/ErrorLogView.swift @@ -37,7 +37,7 @@ struct ErrorLogView: View { HStack(alignment: .top) { Group { if let storeApp = error.storeApp { - AppIconView(iconUrl: storeApp.iconURL, size: 50) + AppIconView(iconUrl: storeApp.iconURL, isSideStore: storeApp.bundleIdentifier == Bundle.Info.appbundleIdentifier, size: 50) } else { ZStack { RoundedRectangle(cornerRadius: 50*0.234, style: .continuous)