0

我正在 SwiftUI 中开发一个应用程序来管理一个虚拟数据中心(服务器、防火墙规则、负载均衡器......)我附加的代码是应用程序的摘录,以显示我当前面临的问题,我无法自己解决。问题(或 SwiftUI 错误?)如下:

  • a) 我无法在 Picker 中选择一个值两次
  • b)当我尝试在我的表单中隐藏某些字段时出现奇怪的行为

使用附加代码复制此问题的方法如下:

  1. 运行应用程序
  2. 转到选项卡创建
  3. 点击防火墙策略创建一个新的
  4. 单击选择器协议并更改值(例如 UDP)
  5. 尝试再次更改该值(例如 TCP)。然后,问题 a) 出现了。选择器显示为“已选择”,但它不起作用
  6. 转到选择器操作并将值更改为拒绝,然后表单中的某些行被隐藏(预期行为)
  7. 现在,尝试再次将选择器操作更改为允许,然后 b) 出现问题,我得到一个奇怪的视图更改和一个空白屏幕

我在 MacOS 10.15.2 上使用 Xcode 11.3 运行它。欢迎任何帮助或提示!

import SwiftUI

struct ContentView: View {
    @State var selectedTab = 1
    var body: some View {
        TabView(selection: $selectedTab){
            CreateView(selectedTab: $selectedTab)
                .tabItem {
                    Image(systemName: "plus")
                    Text("Create")
                }.tag(0)
            ListView()
                .tabItem {
                    Image(systemName: "cloud")
                    Text("List")
                }.tag(1)
        }
    }
}


struct CreateView: View {
    @Binding var selectedTab: Int
    var body: some View {
        VStack{
            NavigationView{
                List{
                    Text("Server")
                    NavigationLink(destination: CreateFirewallPolicyView(selectedTab: $selectedTab)){
                        Text("Firewall Policy")
                    }
                }
                .navigationBarTitle("Select the element you want to create", displayMode: .inline)
           }
        }
    }
}

struct ListView: View {
    var body: some View {
        NavigationView{
            List{
                Section(header: Text("Servers")){
                    Text("Server 1")
                    Text("Server 2")
                }
                Section(header: Text("Firewall policies")){
                    Text("Firewall 1")
                    Text("Firewall 2")
                }
            }
            .navigationBarTitle("My virtual datacenter", displayMode: .large)
        }
    }
}



struct CreateFirewallPolicyView: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

    @Binding var selectedTab: Int

    @State private var name: String = ""
    @State private var allowed_ip: String = ""
    @State private var ports: String = ""
    @State private var description: String = ""
    @State private var selectedAction = RuleAction.allow
    @State private var selectedProtocol = NetworkProtocol.tcp
    @State private var rules: [Rule] = []

    var body: some View {
        Form {
            Section(header: Text("Name of the firewall policy")){
                TextField("Nombre", text: $name)
            }
            Section(header: Text("New rule")){
                Picker(selection: $selectedAction, label: Text("Action")) {
                    ForEach(RuleAction.allCases, id:\.self) { fw_action in
                        Text(fw_action.name)
                    }
                }
                if (selectedAction == RuleAction.allow){
                    TextField("Allowed IP", text: $allowed_ip)
                    Picker(selection: $selectedProtocol, label: Text("Protocol")) {
                        ForEach(NetworkProtocol.allCases, id:\.self) { fw_protocol in
                            Text(fw_protocol.name)
                        }
                    }
                    TextField("Ports", text: $ports)
                }
                TextField("Description", text: $description)
                Button(action: {
                    if self.selectedAction == RuleAction.deny{
                        self.ports = ""
                        self.allowed_ip = ""
                        self.selectedProtocol = NetworkProtocol.any
                    }
                    self.rules.append(Rule(id: UUID().uuidString, protocol: self.selectedProtocol, port: (self.ports.isEmpty ? nil : self.ports), source: (self.allowed_ip.isEmpty ? "0.0.0.0" : self.allowed_ip), description: (self.description.isEmpty ? nil : self.description), action: self.selectedAction))
                    self.allowed_ip = ""
                    self.ports = ""
                    self.description = ""
                    self.selectedAction = RuleAction.allow
                    self.selectedProtocol = NetworkProtocol.tcp
                }) {
                    HStack{
                        Spacer()
                        Text("Add new rule")
                    }.disabled(self.selectedAction == RuleAction.allow && (self.selectedProtocol == NetworkProtocol.tcp || self.selectedProtocol == NetworkProtocol.udp || self.selectedProtocol == NetworkProtocol.tcp_udp) && self.ports.isEmpty)

                }
            }
            Section(header: Text("Rules to add")){
                ForEach(self.rules, id:\.self) { rule in
                    Text("\(rule.action.rawValue.capitalized) - \(rule.source ?? "all") - \(rule.protocol.rawValue) - \(rule.port ?? "")")
                }.onDelete(perform: delete)
            }

        }
        .navigationBarTitle("Create Firewall Policy")
        .navigationBarBackButtonHidden(true)
        .navigationBarItems(
            leading:
                Button(action: {
                    self.presentationMode.wrappedValue.dismiss()
                }) {
                    Text("Cancel")
                },
            trailing:
                Button(action: {
                    print("Create")
                }) {
                    Text("Create")
                }
                .disabled(name.isEmpty || rules.count == 0)
        )
    }

    func delete(at offsets: IndexSet) {
        rules.remove(atOffsets: offsets)
    }
}

struct Rule:Codable, Hashable, Identifiable{
    let id: String
    var `protocol`: NetworkProtocol
    var port: String?
    var portFrom: Int?
    var portTo: Int?
    var source: String?
    var description: String?
    var action: RuleAction
}

enum NetworkProtocol: String, Codable, Hashable, CaseIterable{
    case tcp = "TCP"
    case udp = "UDP"
    case icmp = "ICMP"
    case tcp_udp = "TCP/UDP"
    case ipsec = "IPSEC"
    case gre = "GRE"
    case any = "ANY"
    var name: String {
        return "\(self.rawValue)"
    }
}

enum RuleAction: String, Codable, Hashable, CaseIterable{
    case allow
    case deny
    var name: String {
        return "\(self)".capitalized
    }
}
4

0 回答 0