diff --git a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/OperatorView.swift b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/OperatorView.swift index 6be5a24406..91b5316424 100644 --- a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/OperatorView.swift +++ b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/OperatorView.swift @@ -16,13 +16,13 @@ struct OperatorView: View { @EnvironmentObject var theme: AppTheme let serverProtocol: ServerProtocol @Binding var serverOperator: ServerOperator // Binding - + @State var serverOperatorToEdit: ServerOperator var servers: [ServerCfg] // State / Binding var proto: String { serverProtocol.rawValue.uppercased() } var body: some View { - return VStack { + VStack { List { Section(header: Text("Operator").foregroundColor(theme.colors.secondary)) { Text(serverOperator.name) @@ -32,6 +32,10 @@ struct OperatorView: View { useOperatorSection() } } + .modifier(BackButton(disabled: Binding.constant(false)) { + serverOperator = serverOperatorToEdit + dismiss() + }) } private func infoViewLink() -> some View { @@ -48,19 +52,19 @@ struct OperatorView: View { private func useOperatorSection() -> some View { Section(header: Text("Use operator").foregroundColor(theme.colors.secondary)) { conditionsViewLink() - if let reviewDeadline = serverOperator.latestConditionsAcceptance.reviewDeadline { + if let reviewDeadline = serverOperatorToEdit.latestConditionsAcceptance.reviewDeadline { infoRow("Review until", deadlineTimestamp(reviewDeadline)) } - Toggle("Use operator", isOn: $serverOperator.enabled) - .disabled(!serverOperator.latestConditionsAcceptance.usageAllowed) - .foregroundColor(!serverOperator.latestConditionsAcceptance.usageAllowed ? theme.colors.secondary : theme.colors.onBackground) + Toggle("Use operator", isOn: $serverOperatorToEdit.enabled) + .disabled(!serverOperatorToEdit.latestConditionsAcceptance.usageAllowed) + .foregroundColor(!serverOperatorToEdit.latestConditionsAcceptance.usageAllowed ? theme.colors.secondary : theme.colors.onBackground) Group { - Toggle("for storage", isOn: $serverOperator.roles.storage) - Toggle("as proxy", isOn: $serverOperator.roles.proxy) + Toggle("for storage", isOn: $serverOperatorToEdit.roles.storage) + Toggle("as proxy", isOn: $serverOperatorToEdit.roles.proxy) } .padding(.leading, 24) - .disabled(!serverOperator.enabled) - .foregroundColor(!serverOperator.enabled ? theme.colors.secondary : theme.colors.onBackground) + .disabled(!serverOperatorToEdit.enabled) + .foregroundColor(!serverOperatorToEdit.enabled ? theme.colors.secondary : theme.colors.onBackground) } } @@ -73,7 +77,7 @@ struct OperatorView: View { @ViewBuilder private func conditionsViewLink() -> some View { NavigationLink() { - UsageConditionsView(serverOperator: $serverOperator) + UsageConditionsView(serverOperator: $serverOperatorToEdit, serverOperatorToEdit: serverOperatorToEdit) .navigationBarTitle("Conditions of use") .modifier(ThemedBackground(grouped: true)) .navigationBarTitleDisplayMode(.large) @@ -92,7 +96,7 @@ struct OperatorInfoView: View { var serverOperator: ServerOperator var body: some View { - return VStack { + VStack { List { Section(header: Text("Description").foregroundColor(theme.colors.secondary)) { Text(serverOperator.info.description) @@ -109,6 +113,7 @@ struct UsageConditionsView: View { @Environment(\.dismiss) var dismiss: DismissAction @EnvironmentObject var theme: AppTheme @Binding var serverOperator: ServerOperator + @State var serverOperatorToEdit: ServerOperator let conditionsText = """ Lorem ipsum odor amet, consectetuer adipiscing elit. Blandit mauris massa tempor ac; maximus accumsan magnis. Sollicitudin maximus tempor luctus sociosqu turpis dictum per imperdiet porttitor. Efficitur mattis fusce curae id efficitur. Non bibendum elementum faucibus vehicula morbi pulvinar. Accumsan habitant tincidunt sollicitudin taciti ad urna potenti velit. Primis laoreet pharetra magnis est dolor proin viverra. @@ -123,7 +128,7 @@ struct UsageConditionsView: View { """ var body: some View { - return VStack { + VStack { List { Section { Text(conditionsText) @@ -136,7 +141,8 @@ struct UsageConditionsView: View { Button { // Should call api to save state here, not when saving all servers // (It's counterintuitive to lose to closed sheet or Reset) - serverOperator.latestConditionsAcceptance = .accepted + serverOperatorToEdit.latestConditionsAcceptance = .accepted + serverOperator = serverOperatorToEdit dismiss() } label: { Text("Accept conditions") @@ -152,6 +158,7 @@ struct UsageConditionsView: View { OperatorView( serverProtocol: .smp, serverOperator: Binding.constant(ServerOperator.sampleData1), + serverOperatorToEdit: ServerOperator.sampleData1, servers: [ServerCfg.sampleData.preset] ) } diff --git a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/ProtocolServersView.swift b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/ProtocolServersView.swift index 073752a941..f75879ed2f 100644 --- a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/ProtocolServersView.swift +++ b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/ProtocolServersView.swift @@ -17,6 +17,7 @@ struct ProtocolServersView: View { @EnvironmentObject var theme: AppTheme @Environment(\.editMode) private var editMode let serverProtocol: ServerProtocol + @State private var serverOperators: [ServerOperator] = [] @State private var currServers: [ServerCfg] = [] @State private var presetServers: [ServerCfg] = [] @State private var configuredServers: [ServerCfg] = [] @@ -160,6 +161,7 @@ struct ProtocolServersView: View { // this condition is needed to prevent re-setting the servers when exiting single server view if justOpened { do { + serverOperators = [ServerOperator.sampleData1, ServerOperator.sampleData2] let r = try getUserProtoServers(serverProtocol) currServers = r.protoServers presetServers = r.presetServers @@ -178,26 +180,10 @@ struct ProtocolServersView: View { } @ViewBuilder private func operatorsSection() -> some View { - let operator1 = ServerOperator.sampleData1 - let operator2 = ServerOperator.sampleData2 let servers = [ServerCfg.sampleData.preset, ServerCfg.sampleData.untested] Section { - NavigationLink() { - OperatorView(serverProtocol: .smp, serverOperator: Binding.constant(operator1), servers: servers) - .navigationBarTitle("\(operator1.name) servers") - .modifier(ThemedBackground(grouped: true)) - .navigationBarTitleDisplayMode(.large) - } label: { - Text(operator1.name) - } - - NavigationLink() { - OperatorView(serverProtocol: .smp, serverOperator: Binding.constant(operator2), servers: servers) - .navigationBarTitle("\(operator2.name) servers") - .modifier(ThemedBackground(grouped: true)) - .navigationBarTitleDisplayMode(.large) - } label: { - Text(operator2.name) + ForEach($serverOperators) { srvOperator in + serverOperatorView(srvOperator, servers) } } header: { Text("Operators") @@ -205,6 +191,23 @@ struct ProtocolServersView: View { } } + @ViewBuilder private func serverOperatorView(_ serverOperator: Binding, _ servers: [ServerCfg]) -> some View { + let srvOperator = serverOperator.wrappedValue + NavigationLink() { + OperatorView( + serverProtocol: .smp, + serverOperator: serverOperator, + serverOperatorToEdit: srvOperator, + servers: servers + ) + .navigationBarTitle("\(srvOperator.name) servers") + .modifier(ThemedBackground(grouped: true)) + .navigationBarTitleDisplayMode(.large) + } label: { + Text(srvOperator.name) + } + } + private func partitionServers(_ servers: [ServerCfg]) { configuredServers = servers.filter { $0.preset || $0.enabled } otherServers = servers.filter { !($0.preset || $0.enabled) } diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index a03123173b..d6c4b5cc43 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -1216,7 +1216,7 @@ public enum UsageConditionsAcceptance: Decodable, Hashable { } } -public struct ServerOperator: Decodable { +public struct ServerOperator: Identifiable, Decodable { public var operatorId: Int64 public var name: String public var info: ServerOperatorInfo @@ -1224,6 +1224,8 @@ public struct ServerOperator: Decodable { public var enabled: Bool public var roles: ServerRoles + public var id: Int64 { operatorId } + public static var sampleData1 = ServerOperator( operatorId: 1, name: "SimpleX Chat",