mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-10-31 22:28:58 +00:00
Add icons + icon selector
This commit is contained in:
parent
df2d383b8a
commit
846184ae58
16 changed files with 222 additions and 17 deletions
|
@ -21,6 +21,7 @@
|
|||
9FBFE63D292A715500C250E9 /* IceCubesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */; };
|
||||
9FBFE641292A715600C250E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9FBFE640292A715600C250E9 /* Assets.xcassets */; };
|
||||
9FBFE64E292A72BD00C250E9 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9FBFE64D292A72BD00C250E9 /* Network */; };
|
||||
9FE151A6293C90F900E9683D /* IconSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FE151A5293C90F900E9683D /* IconSelectorView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
|
@ -40,6 +41,7 @@
|
|||
9FBFE63C292A715500C250E9 /* IceCubesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IceCubesApp.swift; sourceTree = "<group>"; };
|
||||
9FBFE640292A715600C250E9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
9FBFE642292A715600C250E9 /* IceCubesApp.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = IceCubesApp.entitlements; sourceTree = "<group>"; };
|
||||
9FE151A5293C90F900E9683D /* IconSelectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconSelectorView.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -82,8 +84,8 @@
|
|||
9FAE4AC9293783A200772766 /* Tabs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9FE151A4293C90EA00E9683D /* Settings */,
|
||||
9F398AB229360A4C00A889F2 /* TimelineTab.swift */,
|
||||
9FAE4ACA293783B000772766 /* SettingsTab.swift */,
|
||||
);
|
||||
path = Tabs;
|
||||
sourceTree = "<group>";
|
||||
|
@ -137,6 +139,15 @@
|
|||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9FE151A4293C90EA00E9683D /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9FAE4ACA293783B000772766 /* SettingsTab.swift */,
|
||||
9FE151A5293C90F900E9683D /* IconSelectorView.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
@ -218,6 +229,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9FE151A6293C90F900E9683D /* IconSelectorView.swift in Sources */,
|
||||
9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */,
|
||||
9FAE4AD32937A0C600772766 /* AppAccountsManager.swift in Sources */,
|
||||
9F398AB329360A4C00A889F2 /* TimelineTab.swift in Sources */,
|
||||
|
@ -342,6 +354,7 @@
|
|||
9FBFE649292A715600C250E9 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIconAlternate1 AppIconAlternate2 AppIconAlternate3 AppIconAlternate4";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
||||
|
@ -381,6 +394,7 @@
|
|||
9FBFE64A292A715600C250E9 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIconAlternate1 AppIconAlternate2 AppIconAlternate3 AppIconAlternate4";
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
||||
|
|
54
IceCubesApp/App/Tabs/Settings/IconSelectorView.swift
Normal file
54
IceCubesApp/App/Tabs/Settings/IconSelectorView.swift
Normal file
|
@ -0,0 +1,54 @@
|
|||
import SwiftUI
|
||||
|
||||
struct IconSelectorView: View {
|
||||
enum Icon: String, CaseIterable, Identifiable {
|
||||
var id: String {
|
||||
self.rawValue
|
||||
}
|
||||
|
||||
case primary = "AppIcon"
|
||||
case alternate1 = "AppIconAlternate1"
|
||||
case alternate2 = "AppIconAlternate2"
|
||||
case alternate3 = "AppIconAlternate3"
|
||||
case alternate4 = "AppIconAlternate4"
|
||||
}
|
||||
|
||||
@State private var currentIcon = UIApplication.shared.alternateIconName ?? Icon.primary.rawValue
|
||||
|
||||
private let columns = [GridItem(.adaptive(minimum: 125, maximum: 1024))]
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading) {
|
||||
LazyVGrid(columns: columns, spacing: 6) {
|
||||
ForEach(Icon.allCases) { icon in
|
||||
Button {
|
||||
currentIcon = icon.rawValue
|
||||
if icon.rawValue == Icon.primary.rawValue {
|
||||
UIApplication.shared.setAlternateIconName(nil)
|
||||
} else {
|
||||
UIApplication.shared.setAlternateIconName(icon.rawValue)
|
||||
}
|
||||
} label: {
|
||||
ZStack(alignment: .bottomTrailing) {
|
||||
Image(uiImage: .init(named: icon.rawValue)!)
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(minHeight: 125, maxHeight: 1024)
|
||||
.cornerRadius(6)
|
||||
.shadow(radius: 3)
|
||||
if icon.rawValue == currentIcon {
|
||||
Image(systemName: "checkmark.seal.fill")
|
||||
.padding(4)
|
||||
.tint(.green)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(6)
|
||||
.navigationTitle("Icons")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,11 +12,35 @@ struct SettingsTabs: View {
|
|||
|
||||
@State private var signInInProgress = false
|
||||
@State private var accountData: Account?
|
||||
@State private var instanceData: Instance?
|
||||
@State private var signInServer = IceCubesApp.defaultServer
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
appSection
|
||||
accountSection
|
||||
instanceSection
|
||||
}
|
||||
.onOpenURL(perform: { url in
|
||||
Task {
|
||||
await continueSignIn(url: url)
|
||||
}
|
||||
})
|
||||
.navigationTitle(Text("Settings"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
.task {
|
||||
if appAccountsManager.currentAccount.oauthToken != nil {
|
||||
signInInProgress = true
|
||||
await refreshAccountInfo()
|
||||
await refreshInstanceInfo()
|
||||
signInInProgress = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var accountSection: some View {
|
||||
Section("Account") {
|
||||
if let accountData {
|
||||
VStack(alignment: .leading) {
|
||||
|
@ -34,19 +58,33 @@ struct SettingsTabs: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onOpenURL(perform: { url in
|
||||
Task {
|
||||
await continueSignIn(url: url)
|
||||
|
||||
@ViewBuilder
|
||||
private var instanceSection: some View {
|
||||
if let instanceData {
|
||||
Section("Instance info") {
|
||||
LabeledContent("Name", value: instanceData.title)
|
||||
Text(instanceData.shortDescription)
|
||||
LabeledContent("Email", value: instanceData.email)
|
||||
LabeledContent("Version", value: instanceData.version)
|
||||
LabeledContent("Users", value: "\(instanceData.stats.userCount)")
|
||||
LabeledContent("Status", value: "\(instanceData.stats.statusCount)")
|
||||
LabeledContent("Domains", value: "\(instanceData.stats.domainCount)")
|
||||
}
|
||||
})
|
||||
.navigationTitle(Text("Settings"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
.task {
|
||||
if appAccountsManager.currentAccount.oauthToken != nil {
|
||||
signInInProgress = true
|
||||
await refreshAccountInfo()
|
||||
signInInProgress = false
|
||||
}
|
||||
|
||||
private var appSection: some View {
|
||||
Section("App") {
|
||||
NavigationLink(destination: IconSelectorView()) {
|
||||
Label {
|
||||
Text("Icon selector")
|
||||
} icon: {
|
||||
Image(uiImage: .init(named: UIApplication.shared.alternateIconName ?? "AppIcon")!)
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25)
|
||||
.cornerRadius(4)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +106,7 @@ struct SettingsTabs: View {
|
|||
|
||||
private var signOutButton: some View {
|
||||
Button {
|
||||
instanceData = nil
|
||||
accountData = nil
|
||||
appAccountsManager.delete(account: appAccountsManager.currentAccount)
|
||||
} label: {
|
||||
|
@ -91,6 +130,7 @@ struct SettingsTabs: View {
|
|||
let oauthToken = try await client.continueOauthFlow(url: url)
|
||||
appAccountsManager.add(account: AppAccount(server: client.server, oauthToken: oauthToken))
|
||||
await refreshAccountInfo()
|
||||
await refreshInstanceInfo()
|
||||
signInInProgress = false
|
||||
} catch {
|
||||
signInInProgress = false
|
||||
|
@ -100,4 +140,8 @@ struct SettingsTabs: View {
|
|||
private func refreshAccountInfo() async {
|
||||
accountData = try? await client.get(endpoint: Accounts.verifyCredentials)
|
||||
}
|
||||
|
||||
private func refreshInstanceInfo() async {
|
||||
instanceData = try? await client.get(endpoint: Instances.instance)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "icon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 986 KiB |
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "icon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.5 MiB |
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "icon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "icon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1,016 KiB |
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "icon.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 1.5 MiB |
18
Packages/Models/Sources/Models/Instance.swift
Normal file
18
Packages/Models/Sources/Models/Instance.swift
Normal file
|
@ -0,0 +1,18 @@
|
|||
import Foundation
|
||||
|
||||
public struct Instance: Codable {
|
||||
public struct Stats: Codable {
|
||||
public let userCount: Int
|
||||
public let statusCount: Int
|
||||
public let domainCount: Int
|
||||
}
|
||||
|
||||
public let title: String
|
||||
public let shortDescription: String
|
||||
public let email: String
|
||||
public let version: String
|
||||
public let stats: Stats
|
||||
public let languages: [String]
|
||||
public let registrations: Bool
|
||||
public let thumbnail: URL?
|
||||
}
|
16
Packages/Network/Sources/Network/Endpoint/Instances.swift
Normal file
16
Packages/Network/Sources/Network/Endpoint/Instances.swift
Normal file
|
@ -0,0 +1,16 @@
|
|||
import Foundation
|
||||
|
||||
public enum Instances: Endpoint {
|
||||
case instance
|
||||
|
||||
public func path() -> String {
|
||||
switch self {
|
||||
case .instance:
|
||||
return "instance"
|
||||
}
|
||||
}
|
||||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
nil
|
||||
}
|
||||
}
|
|
@ -1,2 +1,4 @@
|
|||
# IceCubesApp
|
||||
A SwiftUI Mastodon client
|
||||
|
||||
![Icon](IceCubesApp/Resources/Assets.xcassets/AppIcon.appiconset/icon.png?)
|
||||
|
|
Loading…
Reference in a new issue