diff --git a/IceCubesApp/App/IceCubesApp.swift b/IceCubesApp/App/IceCubesApp.swift index 65784022..bc9f41cc 100644 --- a/IceCubesApp/App/IceCubesApp.swift +++ b/IceCubesApp/App/IceCubesApp.swift @@ -11,6 +11,7 @@ struct IceCubesApp: App { @Environment(\.scenePhase) private var scenePhase @StateObject private var appAccountsManager = AppAccountsManager() + @StateObject private var currenInstance = CurrentInstance() @StateObject private var currentAccount = CurrentAccount() @StateObject private var watcher = StreamWatcher() @StateObject private var quickLook = QuickLook() @@ -56,6 +57,7 @@ struct IceCubesApp: App { .environmentObject(appAccountsManager.currentClient) .environmentObject(quickLook) .environmentObject(currentAccount) + .environmentObject(currenInstance) .environmentObject(theme) .environmentObject(watcher) .quickLookPreview($quickLook.url, in: quickLook.urls) @@ -67,6 +69,7 @@ struct IceCubesApp: App { private func setNewClientsInEnv(client: Client) { currentAccount.setClient(client: client) + currenInstance.setClient(client: client) watcher.setClient(client: client) } diff --git a/IceCubesApp/App/Tabs/Settings/SettingsTab.swift b/IceCubesApp/App/Tabs/Settings/SettingsTab.swift index c2007ea9..2caea9f9 100644 --- a/IceCubesApp/App/Tabs/Settings/SettingsTab.swift +++ b/IceCubesApp/App/Tabs/Settings/SettingsTab.swift @@ -9,12 +9,12 @@ import DesignSystem struct SettingsTabs: View { @Environment(\.openURL) private var openURL @EnvironmentObject private var client: Client + @EnvironmentObject private var currentInstance: CurrentInstance @EnvironmentObject private var appAccountsManager: AppAccountsManager @EnvironmentObject private var theme: Theme @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 { @@ -37,7 +37,7 @@ struct SettingsTabs: View { if appAccountsManager.currentAccount.oauthToken != nil { signInInProgress = true await refreshAccountInfo() - await refreshInstanceInfo() + await currentInstance.fetchCurrentInstance() signInInProgress = false } } @@ -77,7 +77,7 @@ struct SettingsTabs: View { @ViewBuilder private var instanceSection: some View { - if let instanceData { + if let instanceData = currentInstance.instance { Section("Instance info") { LabeledContent("Name", value: instanceData.title) Text(instanceData.shortDescription) @@ -87,6 +87,12 @@ struct SettingsTabs: View { LabeledContent("Posts", value: "\(instanceData.stats.statusCount)") LabeledContent("Domains", value: "\(instanceData.stats.domainCount)") } + + Section("Instance rules") { + ForEach(instanceData.rules) { rule in + Text(rule.text) + } + } } } @@ -127,7 +133,6 @@ struct SettingsTabs: View { private var signOutButton: some View { Button { - instanceData = nil accountData = nil appAccountsManager.delete(account: appAccountsManager.currentAccount) } label: { @@ -151,7 +156,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() + await currentInstance.fetchCurrentInstance() signInInProgress = false } catch { signInInProgress = false @@ -161,8 +166,4 @@ 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) - } } diff --git a/Packages/Env/Sources/Env/CurrentInstance.swift b/Packages/Env/Sources/Env/CurrentInstance.swift new file mode 100644 index 00000000..b0c956d6 --- /dev/null +++ b/Packages/Env/Sources/Env/CurrentInstance.swift @@ -0,0 +1,28 @@ +import Foundation +import Models +import Network + +@MainActor +public class CurrentInstance: ObservableObject { + @Published public private(set) var instance: Instance? + + private var client: Client? + + public init() { + + } + + public func setClient(client: Client) { + self.client = client + Task { + await fetchCurrentInstance() + } + } + + public func fetchCurrentInstance() async { + guard let client = client else { return } + Task { + instance = try? await client.get(endpoint: Instances.instance) + } + } +} diff --git a/Packages/Models/Sources/Models/Instance.swift b/Packages/Models/Sources/Models/Instance.swift index 631e05ea..1a470a4e 100644 --- a/Packages/Models/Sources/Models/Instance.swift +++ b/Packages/Models/Sources/Models/Instance.swift @@ -7,6 +7,28 @@ public struct Instance: Codable { public let domainCount: Int } + public struct Configuration: Codable { + public struct Statuses: Codable { + public let maxCharacters: Int + public let maxMediaAttachments: Int + } + + public struct Polls: Codable { + public let maxOptions: Int + public let maxCharactersPerOption: Int + public let minExpiration: Int + public let maxExpiration: Int + } + + public let statuses: Statuses + public let polls: Polls + } + + public struct Rule: Codable, Identifiable { + public let id: String + public let text: String + } + public let title: String public let shortDescription: String public let email: String @@ -15,4 +37,6 @@ public struct Instance: Codable { public let languages: [String] public let registrations: Bool public let thumbnail: URL? + public let configuration: Configuration + public let rules: [Rule] } diff --git a/Packages/Status/Sources/Status/Editor/StatusEditorView.swift b/Packages/Status/Sources/Status/Editor/StatusEditorView.swift index ef2574ae..446823de 100644 --- a/Packages/Status/Sources/Status/Editor/StatusEditorView.swift +++ b/Packages/Status/Sources/Status/Editor/StatusEditorView.swift @@ -11,6 +11,7 @@ import NukeUI public struct StatusEditorView: View { @EnvironmentObject private var quicklook: QuickLook @EnvironmentObject private var client: Client + @EnvironmentObject private var currentInstance: CurrentInstance @EnvironmentObject private var currentAccount: CurrentAccount @Environment(\.dismiss) private var dismiss @@ -195,10 +196,12 @@ public struct StatusEditorView: View { } label: { Image(systemName: "number") } + + visibilityMenu Spacer() - visibilityMenu + characterCountView } .padding(.horizontal, DS.Constants.layoutPadding) .padding(.vertical, 12) @@ -206,6 +209,12 @@ public struct StatusEditorView: View { } } + private var characterCountView: some View { + Text("\((currentInstance.instance?.configuration.statuses.maxCharacters ?? 500) - viewModel.statusText.string.utf16.count)") + .foregroundColor(.gray) + .font(.callout) + } + private var visibilityMenu: some View { Menu { ForEach(Models.Visibility.allCases, id: \.self) { visibility in