mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-25 17:51:01 +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 */; };
|
9FBFE63D292A715500C250E9 /* IceCubesApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBFE63C292A715500C250E9 /* IceCubesApp.swift */; };
|
||||||
9FBFE641292A715600C250E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9FBFE640292A715600C250E9 /* Assets.xcassets */; };
|
9FBFE641292A715600C250E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9FBFE640292A715600C250E9 /* Assets.xcassets */; };
|
||||||
9FBFE64E292A72BD00C250E9 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9FBFE64D292A72BD00C250E9 /* Network */; };
|
9FBFE64E292A72BD00C250E9 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = 9FBFE64D292A72BD00C250E9 /* Network */; };
|
||||||
|
9FE151A6293C90F900E9683D /* IconSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FE151A5293C90F900E9683D /* IconSelectorView.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
9FBFE63C292A715500C250E9 /* IceCubesApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IceCubesApp.swift; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -82,8 +84,8 @@
|
||||||
9FAE4AC9293783A200772766 /* Tabs */ = {
|
9FAE4AC9293783A200772766 /* Tabs */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
9FE151A4293C90EA00E9683D /* Settings */,
|
||||||
9F398AB229360A4C00A889F2 /* TimelineTab.swift */,
|
9F398AB229360A4C00A889F2 /* TimelineTab.swift */,
|
||||||
9FAE4ACA293783B000772766 /* SettingsTab.swift */,
|
|
||||||
);
|
);
|
||||||
path = Tabs;
|
path = Tabs;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -137,6 +139,15 @@
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
9FE151A4293C90EA00E9683D /* Settings */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9FAE4ACA293783B000772766 /* SettingsTab.swift */,
|
||||||
|
9FE151A5293C90F900E9683D /* IconSelectorView.swift */,
|
||||||
|
);
|
||||||
|
path = Settings;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
|
@ -218,6 +229,7 @@
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
9FE151A6293C90F900E9683D /* IconSelectorView.swift in Sources */,
|
||||||
9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */,
|
9FAE4ACB293783B000772766 /* SettingsTab.swift in Sources */,
|
||||||
9FAE4AD32937A0C600772766 /* AppAccountsManager.swift in Sources */,
|
9FAE4AD32937A0C600772766 /* AppAccountsManager.swift in Sources */,
|
||||||
9F398AB329360A4C00A889F2 /* TimelineTab.swift in Sources */,
|
9F398AB329360A4C00A889F2 /* TimelineTab.swift in Sources */,
|
||||||
|
@ -342,6 +354,7 @@
|
||||||
9FBFE649292A715600C250E9 /* Debug */ = {
|
9FBFE649292A715600C250E9 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIconAlternate1 AppIconAlternate2 AppIconAlternate3 AppIconAlternate4";
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
||||||
|
@ -381,6 +394,7 @@
|
||||||
9FBFE64A292A715600C250E9 /* Release */ = {
|
9FBFE64A292A715600C250E9 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "AppIconAlternate1 AppIconAlternate2 AppIconAlternate3 AppIconAlternate4";
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_ENTITLEMENTS = IceCubesApp/IceCubesApp.entitlements;
|
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,27 +12,15 @@ struct SettingsTabs: View {
|
||||||
|
|
||||||
@State private var signInInProgress = false
|
@State private var signInInProgress = false
|
||||||
@State private var accountData: Account?
|
@State private var accountData: Account?
|
||||||
|
@State private var instanceData: Instance?
|
||||||
@State private var signInServer = IceCubesApp.defaultServer
|
@State private var signInServer = IceCubesApp.defaultServer
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationStack {
|
NavigationStack {
|
||||||
Form {
|
Form {
|
||||||
Section("Account") {
|
appSection
|
||||||
if let accountData {
|
accountSection
|
||||||
VStack(alignment: .leading) {
|
instanceSection
|
||||||
Text(appAccountsManager.currentAccount.server)
|
|
||||||
.font(.headline)
|
|
||||||
Text(accountData.displayName)
|
|
||||||
Text(accountData.username)
|
|
||||||
.font(.footnote)
|
|
||||||
.foregroundColor(.gray)
|
|
||||||
}
|
|
||||||
signOutButton
|
|
||||||
} else {
|
|
||||||
TextField("Mastodon server", text: $signInServer)
|
|
||||||
signInButton
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.onOpenURL(perform: { url in
|
.onOpenURL(perform: { url in
|
||||||
Task {
|
Task {
|
||||||
|
@ -46,11 +34,61 @@ struct SettingsTabs: View {
|
||||||
if appAccountsManager.currentAccount.oauthToken != nil {
|
if appAccountsManager.currentAccount.oauthToken != nil {
|
||||||
signInInProgress = true
|
signInInProgress = true
|
||||||
await refreshAccountInfo()
|
await refreshAccountInfo()
|
||||||
|
await refreshInstanceInfo()
|
||||||
signInInProgress = false
|
signInInProgress = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var accountSection: some View {
|
||||||
|
Section("Account") {
|
||||||
|
if let accountData {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text(appAccountsManager.currentAccount.server)
|
||||||
|
.font(.headline)
|
||||||
|
Text(accountData.displayName)
|
||||||
|
Text(accountData.username)
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
signOutButton
|
||||||
|
} else {
|
||||||
|
TextField("Mastodon server", text: $signInServer)
|
||||||
|
signInButton
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@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)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var signInButton: some View {
|
private var signInButton: some View {
|
||||||
Button {
|
Button {
|
||||||
signInInProgress = true
|
signInInProgress = true
|
||||||
|
@ -68,6 +106,7 @@ struct SettingsTabs: View {
|
||||||
|
|
||||||
private var signOutButton: some View {
|
private var signOutButton: some View {
|
||||||
Button {
|
Button {
|
||||||
|
instanceData = nil
|
||||||
accountData = nil
|
accountData = nil
|
||||||
appAccountsManager.delete(account: appAccountsManager.currentAccount)
|
appAccountsManager.delete(account: appAccountsManager.currentAccount)
|
||||||
} label: {
|
} label: {
|
||||||
|
@ -91,6 +130,7 @@ struct SettingsTabs: View {
|
||||||
let oauthToken = try await client.continueOauthFlow(url: url)
|
let oauthToken = try await client.continueOauthFlow(url: url)
|
||||||
appAccountsManager.add(account: AppAccount(server: client.server, oauthToken: oauthToken))
|
appAccountsManager.add(account: AppAccount(server: client.server, oauthToken: oauthToken))
|
||||||
await refreshAccountInfo()
|
await refreshAccountInfo()
|
||||||
|
await refreshInstanceInfo()
|
||||||
signInInProgress = false
|
signInInProgress = false
|
||||||
} catch {
|
} catch {
|
||||||
signInInProgress = false
|
signInInProgress = false
|
||||||
|
@ -100,4 +140,8 @@ struct SettingsTabs: View {
|
||||||
private func refreshAccountInfo() async {
|
private func refreshAccountInfo() async {
|
||||||
accountData = try? await client.get(endpoint: Accounts.verifyCredentials)
|
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" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
|
"filename" : "icon.png",
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"platform" : "ios",
|
"platform" : "ios",
|
||||||
"size" : "1024x1024"
|
"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
|
# IceCubesApp
|
||||||
A SwiftUI Mastodon client
|
A SwiftUI Mastodon client
|
||||||
|
|
||||||
|
![Icon](IceCubesApp/Resources/Assets.xcassets/AppIcon.appiconset/icon.png?)
|
||||||
|
|
Loading…
Reference in a new issue