import Libbox import Library import SwiftUI @MainActor public class GroupListViewModel: BaseViewModel { @Published public var groups: [OutboundGroup] = [] private var pendingSelections: [String: String] = [:] override public init() { super.init() isLoading = true } public func connect() { if Variant.screenshotMode { groups = [ OutboundGroup(tag: "my_group", type: "selector", selected: "server", selectable: true, isExpand: true, items: [ OutboundGroupItem(tag: "server", type: "Shadowsocks", urlTestTime: .now, urlTestDelay: 10), OutboundGroupItem(tag: "server2", type: "WireGuard", urlTestTime: .now, urlTestDelay: 20), OutboundGroupItem(tag: "auto", type: "URLTest", urlTestTime: .now, urlTestDelay: 30), ]), OutboundGroup(tag: "Auto", type: "urltest", selected: "Tokyo", selectable: true, isExpand: false, items: [ OutboundGroupItem(tag: "Tokyo", type: "Shadowsocks", urlTestTime: .now, urlTestDelay: 10), OutboundGroupItem(tag: "Singapore", type: "VMess", urlTestTime: .now, urlTestDelay: 20), OutboundGroupItem(tag: "Hong Kong", type: "Trojan", urlTestTime: .now, urlTestDelay: 15), ]), ] isLoading = false } } public func setGroups(_ goGroups: [LibboxOutboundGroup]?) { guard let goGroups else { return } let existingGroups = Dictionary(uniqueKeysWithValues: groups.map { ($0.tag, $0) }) var newGroups = [OutboundGroup]() for goGroup in goGroups { var items = [OutboundGroupItem]() let itemIterator = goGroup.getItems()! while itemIterator.hasNext() { items.append(OutboundGroupItem(itemIterator.next()!)) } var selected = goGroup.selected if let pending = pendingSelections[goGroup.tag] { if goGroup.selected == pending { pendingSelections.removeValue(forKey: goGroup.tag) } else { selected = pending } } let isExpand = existingGroups[goGroup.tag]?.isExpand ?? goGroup.isExpand newGroups.append(OutboundGroup( tag: goGroup.tag, type: goGroup.type, selected: selected, selectable: goGroup.selectable, isExpand: isExpand, items: items )) } groups = newGroups isLoading = false } public func selectOutbound(groupTag: String, outboundTag: String) { if let index = groups.firstIndex(where: { $0.tag == groupTag }) { groups[index].selected = outboundTag } pendingSelections[groupTag] = outboundTag Task { await doSelectOutbound(groupTag: groupTag, outboundTag: outboundTag) } } private nonisolated func doSelectOutbound(groupTag: String, outboundTag: String) async { do { try await LibboxNewStandaloneCommandClient()!.selectOutbound(groupTag, outboundTag: outboundTag) } catch { await MainActor.run { alert = AlertState(action: "select outbound", error: error) } } } public func toggleExpand(groupTag: String) { guard let index = groups.firstIndex(where: { $0.tag == groupTag }) else { return } groups[index].isExpand.toggle() let isExpand = groups[index].isExpand Task { await setGroupExpand(tag: groupTag, isExpand: isExpand) } } private nonisolated func setGroupExpand(tag: String, isExpand: Bool) async { do { try await LibboxNewStandaloneCommandClient()!.setGroupExpand(tag, isExpand: isExpand) } catch { await MainActor.run { alert = AlertState(action: "update group expansion", error: error) } } } public func performURLTest(_ tag: String) { Task { await doURLTest(tag: tag) } } private nonisolated func doURLTest(tag: String) async { do { try await LibboxNewStandaloneCommandClient()!.urlTest(tag) } catch { await MainActor.run { alert = AlertState(action: "run URL test", error: error) } } } }