Alternate app icons

This commit is contained in:
Justin Mazzocchi 2021-03-03 23:22:32 -08:00
parent e245569e1a
commit d0081101bc
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
16 changed files with 303 additions and 22 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -60,6 +60,10 @@
"activity.open-in-default-browser" = "Open in default browser";
"add" = "Add";
"apns-default-message" = "New notification";
"app-icon.brutalist" = "Brutalist";
"app-icon.rainbow-brutalist" = "Rainbow Brutalist";
"app-icon.classic" = "Classic";
"app-icon.rainbow" = "Rainbow";
"add-identity.instance-url" = "Instance URL";
"add-identity.log-in" = "Log in";
"add-identity.browse" = "Browse";
@ -182,6 +186,7 @@
"post" = "Post";
"preferences" = "Preferences";
"preferences.app" = "App Preferences";
"preferences.app-icon" = "App Icon";
"preferences.blocked-domains" = "Blocked Domains";
"preferences.blocked-users" = "Blocked Users";
"preferences.media" = "Media";

View file

@ -185,6 +185,17 @@
D0D2AC5325BCD2BA003D5DF2 /* TagContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D2AC5225BCD2BA003D5DF2 /* TagContentConfiguration.swift */; };
D0D2AC6725BD0484003D5DF2 /* LineChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D2AC6625BD0484003D5DF2 /* LineChartView.swift */; };
D0D4301425F067D600BE5504 /* BlurHash in Frameworks */ = {isa = PBXBuildFile; productRef = D0D4301325F067D600BE5504 /* BlurHash */; };
D0D4301C25F08CFD00BE5504 /* AppIconLight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4301A25F08CFD00BE5504 /* AppIconLight@2x.png */; };
D0D4301D25F08CFD00BE5504 /* AppIconLight@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4301B25F08CFD00BE5504 /* AppIconLight@3x.png */; };
D0D4302D25F0904D00BE5504 /* AppIconPreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D4302C25F0904D00BE5504 /* AppIconPreferencesView.swift */; };
D0D4303C25F0A30600BE5504 /* AppIconClassic@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4303A25F0A30600BE5504 /* AppIconClassic@3x.png */; };
D0D4303D25F0A30600BE5504 /* AppIconClassic@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4303B25F0A30600BE5504 /* AppIconClassic@2x.png */; };
D0D4304825F0AEE600BE5504 /* AppIconRainbow@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4304625F0AEE600BE5504 /* AppIconRainbow@3x.png */; };
D0D4304925F0AEE600BE5504 /* AppIconRainbow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4304725F0AEE600BE5504 /* AppIconRainbow@2x.png */; };
D0D4306425F0B93700BE5504 /* AppIconBrutalist@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4306225F0B93700BE5504 /* AppIconBrutalist@2x.png */; };
D0D4306525F0B93700BE5504 /* AppIconBrutalist@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4306325F0B93700BE5504 /* AppIconBrutalist@3x.png */; };
D0D4307025F0BBA900BE5504 /* AppIconRainbowBrutalist@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4306E25F0BBA900BE5504 /* AppIconRainbowBrutalist@2x.png */; };
D0D4307125F0BBA900BE5504 /* AppIconRainbowBrutalist@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0D4306F25F0BBA900BE5504 /* AppIconRainbowBrutalist@3x.png */; };
D0D93EBA25D9C70400C622ED /* AutocompleteItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D93EB925D9C70400C622ED /* AutocompleteItemView.swift */; };
D0D93EC025D9C71D00C622ED /* AutocompleteItemContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D93EBF25D9C71D00C622ED /* AutocompleteItemContentConfiguration.swift */; };
D0D93EC525D9C75E00C622ED /* AutocompleteItemContentConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D93EBF25D9C71D00C622ED /* AutocompleteItemContentConfiguration.swift */; };
@ -406,6 +417,17 @@
D0D2AC4C25BCD2A9003D5DF2 /* TagTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagTableViewCell.swift; sourceTree = "<group>"; };
D0D2AC5225BCD2BA003D5DF2 /* TagContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TagContentConfiguration.swift; sourceTree = "<group>"; };
D0D2AC6625BD0484003D5DF2 /* LineChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChartView.swift; sourceTree = "<group>"; };
D0D4301A25F08CFD00BE5504 /* AppIconLight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconLight@2x.png"; sourceTree = "<group>"; };
D0D4301B25F08CFD00BE5504 /* AppIconLight@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconLight@3x.png"; sourceTree = "<group>"; };
D0D4302C25F0904D00BE5504 /* AppIconPreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconPreferencesView.swift; sourceTree = "<group>"; };
D0D4303A25F0A30600BE5504 /* AppIconClassic@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconClassic@3x.png"; sourceTree = "<group>"; };
D0D4303B25F0A30600BE5504 /* AppIconClassic@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconClassic@2x.png"; sourceTree = "<group>"; };
D0D4304625F0AEE600BE5504 /* AppIconRainbow@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconRainbow@3x.png"; sourceTree = "<group>"; };
D0D4304725F0AEE600BE5504 /* AppIconRainbow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconRainbow@2x.png"; sourceTree = "<group>"; };
D0D4306225F0B93700BE5504 /* AppIconBrutalist@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconBrutalist@2x.png"; sourceTree = "<group>"; };
D0D4306325F0B93700BE5504 /* AppIconBrutalist@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconBrutalist@3x.png"; sourceTree = "<group>"; };
D0D4306E25F0BBA900BE5504 /* AppIconRainbowBrutalist@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconRainbowBrutalist@2x.png"; sourceTree = "<group>"; };
D0D4306F25F0BBA900BE5504 /* AppIconRainbowBrutalist@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "AppIconRainbowBrutalist@3x.png"; sourceTree = "<group>"; };
D0D93EB925D9C70400C622ED /* AutocompleteItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteItemView.swift; sourceTree = "<group>"; };
D0D93EBF25D9C71D00C622ED /* AutocompleteItemContentConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteItemContentConfiguration.swift; sourceTree = "<group>"; };
D0D93ECF25D9C9ED00C622ED /* AutocompleteItemCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutocompleteItemCollectionViewCell.swift; sourceTree = "<group>"; };
@ -534,6 +556,7 @@
D021A62B25C38570008A0C0D /* AboutView.swift */,
D021A63525C38ADB008A0C0D /* AcknowledgmentsView.swift */,
D02D33EE25EE04CC000A35CC /* AddRemoveFromListsView.swift */,
D0D4302C25F0904D00BE5504 /* AppIconPreferencesView.swift */,
D08E52602579D2E100FA2C5F /* DomainBlocksView.swift */,
D0BEB21024FA2A90001B0F04 /* EditFilterView.swift */,
D0BEB20424FA1107001B0F04 /* FiltersView.swift */,
@ -643,6 +666,7 @@
D047FA7F24C3E21000AF17C5 = {
isa = PBXGroup;
children = (
D0D4301925F08CE600BE5504 /* App Icons */,
D0477F2A25C6EB90005C5368 /* Activities */,
D0C7D45224F76169001EBDBB /* Assets.xcassets */,
D0FE1C9625368A15003EF1EB /* Caches */,
@ -821,6 +845,23 @@
path = Extensions;
sourceTree = "<group>";
};
D0D4301925F08CE600BE5504 /* App Icons */ = {
isa = PBXGroup;
children = (
D0D4306225F0B93700BE5504 /* AppIconBrutalist@2x.png */,
D0D4306325F0B93700BE5504 /* AppIconBrutalist@3x.png */,
D0D4306E25F0BBA900BE5504 /* AppIconRainbowBrutalist@2x.png */,
D0D4306F25F0BBA900BE5504 /* AppIconRainbowBrutalist@3x.png */,
D0D4303B25F0A30600BE5504 /* AppIconClassic@2x.png */,
D0D4303A25F0A30600BE5504 /* AppIconClassic@3x.png */,
D0D4301A25F08CFD00BE5504 /* AppIconLight@2x.png */,
D0D4301B25F08CFD00BE5504 /* AppIconLight@3x.png */,
D0D4304625F0AEE600BE5504 /* AppIconRainbow@3x.png */,
D0D4304725F0AEE600BE5504 /* AppIconRainbow@2x.png */,
);
path = "App Icons";
sourceTree = "<group>";
};
D0E5361A24E3EB4D00FB1CE1 /* Notification Service Extension */ = {
isa = PBXGroup;
children = (
@ -991,8 +1032,18 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D0D4306425F0B93700BE5504 /* AppIconBrutalist@2x.png in Resources */,
D0D4304825F0AEE600BE5504 /* AppIconRainbow@3x.png in Resources */,
D0C7D4C524F7616A001EBDBB /* Localizable.strings in Resources */,
D0C7D4C224F7616A001EBDBB /* Assets.xcassets in Resources */,
D0D4304925F0AEE600BE5504 /* AppIconRainbow@2x.png in Resources */,
D0D4301C25F08CFD00BE5504 /* AppIconLight@2x.png in Resources */,
D0D4306525F0B93700BE5504 /* AppIconBrutalist@3x.png in Resources */,
D0D4303D25F0A30600BE5504 /* AppIconClassic@2x.png in Resources */,
D0D4301D25F08CFD00BE5504 /* AppIconLight@3x.png in Resources */,
D0D4307025F0BBA900BE5504 /* AppIconRainbowBrutalist@2x.png in Resources */,
D0D4307125F0BBA900BE5504 /* AppIconRainbowBrutalist@3x.png in Resources */,
D0D4303C25F0A30600BE5504 /* AppIconClassic@3x.png in Resources */,
D0C7D4C624F7616A001EBDBB /* Localizable.stringsdict in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -1110,6 +1161,7 @@
D08B8D672540DEB200B1EBEF /* ZoomAnimatableView.swift in Sources */,
D0CEC0F725E3303200FEF5A6 /* AnimatingLayoutManager.swift in Sources */,
D08B8D822544D80000B1EBEF /* PollOptionButton.swift in Sources */,
D0D4302D25F0904D00BE5504 /* AppIconPreferencesView.swift in Sources */,
D0C7D4DA24F7616A001EBDBB /* View+Extensions.swift in Sources */,
D07EC81125B232C2006DF726 /* SystemEmoji+Extensions.swift in Sources */,
D035F87D25B7F61600DC75ED /* TimelinesViewController.swift in Sources */,

View file

@ -6,6 +6,90 @@
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>AppIconBrutalist</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIconBrutalist</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>AppIconRainbow</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIconRainbow</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>AppIconRainbowBrutalist</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIconRainbowBrutalist</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIcon</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundleIcons~ipad</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>AppIconBrutalist</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIconBrutalist</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>AppIconRainbow</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIconRainbow</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>AppIconRainbowBrutalist</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIconRainbowBrutalist</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIcon</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>

View file

@ -5,4 +5,8 @@ import Foundation
public struct AlertItem: Identifiable {
public let id = UUID()
public let error: Error
public init(error: Error) {
self.error = error
}
}

View file

@ -0,0 +1,114 @@
// Copyright © 2021 Metabolist. All rights reserved.
import SwiftUI
import ViewModels
struct AppIconPreferencesView: View {
@StateObject var viewModel: PreferencesViewModel
@State var alertItem: AlertItem?
var body: some View {
ScrollView {
LazyVGrid(columns: [
GridItem(.flexible(minimum: .minimumButtonDimension)),
GridItem(.flexible(minimum: .minimumButtonDimension)),
GridItem(.flexible(minimum: .minimumButtonDimension))
]) {
ForEach(AppIcon.allCases) {
cell(appIcon: $0)
}
}
.padding()
}
.alertItem($alertItem)
.navigationTitle("preferences.app-icon")
}
}
private extension AppIconPreferencesView {
@ViewBuilder func cell(appIcon: AppIcon) -> some View {
Button {
set(appIcon: appIcon)
} label: {
VStack {
if let image = appIcon.image {
image
.cornerRadius(.defaultCornerRadius)
.shadow(radius: .defaultShadowRadius)
.padding(.compactSpacing)
.background(appIcon == AppIcon.current ? Color.blue : Color.clear)
.cornerRadius(.defaultCornerRadius)
.padding(.top)
}
Text(appIcon.nameLocalizedStringKey)
.scaledToFill()
.minimumScaleFactor(0.5)
.foregroundColor(.primary)
}
}
}
func set(appIcon: AppIcon) {
UIApplication.shared.setAlternateIconName(appIcon.alternateIconName) { error in
DispatchQueue.main.async {
if let error = error {
alertItem = AlertItem(error: error)
} else {
viewModel.objectWillChange.send()
}
}
}
}
}
enum AppIcon: String, CaseIterable {
case classic = "AppIconClassic"
case rainbow = "AppIconRainbow"
case brutalist = "AppIconBrutalist"
case rainbowBrutalist = "AppIconRainbowBrutalist"
}
extension AppIcon {
static var current: Self? { Self(rawValue: UIApplication.shared.alternateIconName ?? Self.classic.rawValue) }
var nameLocalizedStringKey: LocalizedStringKey {
switch self {
case .classic:
return "app-icon.classic"
case .rainbow:
return "app-icon.rainbow"
case .brutalist:
return "app-icon.brutalist"
case .rainbowBrutalist:
return "app-icon.rainbow-brutalist"
}
}
var alternateIconName: String? {
switch self {
case .classic:
return nil
default:
return rawValue
}
}
var image: Image? {
guard let image = UIImage(named: rawValue) else { return nil }
return Image(uiImage: image)
}
}
extension AppIcon: Identifiable {
var id: Self { self }
}
#if DEBUG
struct AppIconPreferencesView_Previews: PreviewProvider {
static var previews: some View {
AppIconPreferencesView(viewModel: .init(identityContext: .preview))
}
}
#endif

View file

@ -66,29 +66,51 @@ struct PreferencesView: View {
&& viewModel.identityContext.identity.authenticated)
}
Section(header: Text("preferences.app")) {
NavigationLink("preferences.notifications",
destination: NotificationPreferencesView(viewModel: viewModel))
Picker("preferences.status-word",
selection: $identityContext.appPreferences.statusWord) {
ForEach(AppPreferences.StatusWord.allCases) { option in
Text(option.localizedStringKey).tag(option)
Group {
if UIApplication.shared.supportsAlternateIcons {
NavigationLink(destination: AppIconPreferencesView(viewModel: viewModel)) {
HStack {
Text("preferences.app-icon")
Spacer()
if let appIcon = AppIcon.current {
if let image = appIcon.image {
image
.resizable()
.frame(
width: UIFont.preferredFont(forTextStyle: .body).lineHeight,
height: UIFont.preferredFont(forTextStyle: .body).lineHeight)
.cornerRadius(.defaultCornerRadius / 2)
}
Text(appIcon.nameLocalizedStringKey)
.foregroundColor(.secondary)
}
}
}
}
NavigationLink("preferences.notifications",
destination: NotificationPreferencesView(viewModel: viewModel))
Picker("preferences.status-word",
selection: $identityContext.appPreferences.statusWord) {
ForEach(AppPreferences.StatusWord.allCases) { option in
Text(option.localizedStringKey).tag(option)
}
}
Toggle("preferences.show-reblog-and-favorite-counts",
isOn: $identityContext.appPreferences.showReblogAndFavoriteCounts)
Toggle("preferences.require-double-tap-to-reblog",
isOn: $identityContext.appPreferences.requireDoubleTapToReblog)
Toggle("preferences.require-double-tap-to-favorite",
isOn: $identityContext.appPreferences.requireDoubleTapToFavorite)
Toggle("preferences.links.open-in-default-browser",
isOn: $identityContext.appPreferences.openLinksInDefaultBrowser)
if !identityContext.appPreferences.openLinksInDefaultBrowser {
Toggle("preferences.links.use-universal-links",
isOn: $identityContext.appPreferences.useUniversalLinks)
}
if accessibilityReduceMotion {
Toggle("preferences.media.use-system-reduce-motion",
isOn: $identityContext.appPreferences.useSystemReduceMotionForMedia)
}
}
Toggle("preferences.show-reblog-and-favorite-counts",
isOn: $identityContext.appPreferences.showReblogAndFavoriteCounts)
Toggle("preferences.require-double-tap-to-reblog",
isOn: $identityContext.appPreferences.requireDoubleTapToReblog)
Toggle("preferences.require-double-tap-to-favorite",
isOn: $identityContext.appPreferences.requireDoubleTapToFavorite)
Toggle("preferences.links.open-in-default-browser",
isOn: $identityContext.appPreferences.openLinksInDefaultBrowser)
if !identityContext.appPreferences.openLinksInDefaultBrowser {
Toggle("preferences.links.use-universal-links",
isOn: $identityContext.appPreferences.useUniversalLinks)
}
if accessibilityReduceMotion {
Toggle("preferences.media.use-system-reduce-motion",
isOn: $identityContext.appPreferences.useSystemReduceMotionForMedia)
}
Group {
Picker("preferences.media.autoplay.gifs",