core, ios: advanced server config (#1371)

* ios: advanced server config

* simplify UI

* core: ServerCfg

* commit migration, update schema

* add preset servers to response

* return default servers if none saved

* fix test
This commit is contained in:
Evgeny Poberezkin
2022-11-16 15:37:20 +00:00
committed by GitHub
parent f8302e2030
commit 491fe4a9bf
21 changed files with 545 additions and 81 deletions

View File

@@ -319,6 +319,17 @@ func setUserSMPServers(smpServers: [String]) async throws {
try await sendCommandOkResp(.setUserSMPServers(smpServers: smpServers))
}
func testSMPServer(smpServer: String) async throws -> Result<(), SMPTestFailure> {
let r = await chatSendCmd(.testSMPServer(smpServer: smpServer))
if case let .sMPTestResult(testFailure) = r {
if let t = testFailure {
return .failure(t)
}
return .success(())
}
throw r
}
func getChatItemTTL() throws -> ChatItemTTL {
let r = chatSendCmdSync(.apiGetChatItemTTL)
if case let .chatItemTTL(chatItemTTL) = r { return ChatItemTTL(chatItemTTL) }

View File

@@ -40,6 +40,13 @@ struct NetworkAndServers: View {
Text("SMP servers")
}
NavigationLink {
SMPServersView()
.navigationTitle("Your SMP servers")
} label: {
Text("SMP servers (new)")
}
Picker("Use .onion hosts", selection: $onionHosts) {
ForEach(OnionHosts.values, id: \.self) { Text($0.text) }
}

View File

@@ -0,0 +1,105 @@
//
// SMPServerView.swift
// SimpleX (iOS)
//
// Created by Evgeny on 15/11/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct SMPServerView: View {
@State var server: ServerCfg
var body: some View {
if server.preset {
presetServer()
} else {
customServer()
}
}
private func presetServer() -> some View {
return VStack {
List {
Section("Preset server address") {
Text(server.server)
}
useServerSection()
}
}
}
private func customServer() -> some View {
VStack {
List {
Section("Your server address") {
TextEditor(text: $server.server)
.multilineTextAlignment(.leading)
.autocorrectionDisabled(true)
.autocapitalization(.none)
.lineLimit(10)
.frame(height: 108)
.padding(-6)
}
useServerSection()
Section("Add to another device") {
QRCode(uri: server.server)
.listRowInsets(EdgeInsets(top: 12, leading: 12, bottom: 12, trailing: 12))
}
}
}
}
private func useServerSection() -> some View {
Section("Use server") {
HStack {
Button("Test server") {
Task { await testServerConnection(server: $server) }
}
Spacer()
showTestStatus(server: server)
}
Toggle("Enabled", isOn: $server.enabled)
Button("Remove server", role: .destructive) {
}
}
}
}
@ViewBuilder func showTestStatus(server: ServerCfg) -> some View {
switch server.tested {
case .some(true):
Image(systemName: "checkmark")
.foregroundColor(.green)
case .some(false):
Image(systemName: "multiply")
.foregroundColor(.red)
case .none:
Color.clear
}
}
func testServerConnection(server: Binding<ServerCfg>) async {
do {
let r = try await testSMPServer(smpServer: server.wrappedValue.server)
await MainActor.run {
switch r {
case .success: server.wrappedValue.tested = true
case .failure: server.wrappedValue.tested = false
}
}
} catch let error {
await MainActor.run {
server.wrappedValue.tested = false
}
}
}
struct SMPServerView_Previews: PreviewProvider {
static var previews: some View {
SMPServerView(server: ServerCfg.sampleData.custom)
}
}

View File

@@ -0,0 +1,106 @@
//
// SMPServersView.swift
// SimpleX (iOS)
//
// Created by Evgeny on 15/11/2022.
// Copyright © 2022 SimpleX Chat. All rights reserved.
//
import SwiftUI
import SimpleXChat
struct SMPServersView: View {
@Environment(\.editMode) var editMode
@State var servers: [ServerCfg] = [
ServerCfg.sampleData.preset,
ServerCfg.sampleData.custom,
ServerCfg.sampleData.untested,
]
@State var showAddServer = false
@State var showSaveAlert = false
var body: some View {
List {
Section("SMP servers") {
ForEach(servers) { srv in
smpServerView(srv)
}
.onMove { indexSet, offset in
servers.move(fromOffsets: indexSet, toOffset: offset)
}
.onDelete { indexSet in
servers.remove(atOffsets: indexSet)
}
if isEditing {
Button("Add server…") {
showAddServer = true
}
}
}
}
.onChange(of: isEditing) { value in
if value == false {
showSaveAlert = true
}
}
.toolbar { EditButton() }
.confirmationDialog("Add server…", isPresented: $showAddServer, titleVisibility: .hidden) {
Button("Scan server QR code") {
}
Button("Add preset servers") {
}
Button("Enter server manually") {
servers.append(ServerCfg.empty)
}
}
.confirmationDialog("Save servers?", isPresented: $showSaveAlert, titleVisibility: .visible) {
Button("Test & save servers") {
for i in 0..<servers.count {
servers[i].tested = nil
}
Task {
for i in 0..<servers.count {
await testServerConnection(server: $servers[i])
}
}
}
Button("Save servers") {
}
Button("Revert changes") {
}
Button("Cancel", role: .cancel) {
editMode?.wrappedValue = .active
}
}
}
private var isEditing: Bool {
editMode?.wrappedValue.isEditing == true
}
private func smpServerView(_ srv: ServerCfg) -> some View {
NavigationLink {
SMPServerView(server: srv)
.navigationBarTitle("Server")
.navigationBarTitleDisplayMode(.large)
} label: {
let v = Text(srv.server)
HStack {
showTestStatus(server: srv)
.frame(width: 16, alignment: .center)
.padding(.trailing, 4)
if srv.enabled {
v
} else {
(v + Text(" (disabled)")).foregroundColor(.secondary)
}
}
}
}
}
struct SMPServersView_Previews: PreviewProvider {
static var previews: some View {
SMPServersView()
}
}