import Libbox import Library import SwiftUI @MainActor public struct GroupView: View { @State private var group: OutboundGroup @State private var geometryWidth: CGFloat = 300 @State private var alert: Alert? public init(_ group: OutboundGroup) { _group = State(initialValue: group) } private var title: some View { HStack { // Text(group.tag) // .font(.headline) //Text() Text(group.tag) .font(.subheadline) .foregroundColor(.secondary) Text("\(group.items.count)") .font(.subheadline) .padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4)) .background(Color.gray.opacity(0.5)) .cornerRadius(4) Button { group.isExpand = !group.isExpand Task { await setGroupExpand() } } label: { HStack{ if group.isExpand { Image(systemName: "arrow.down.to.line") Text("收起").font(.subheadline) } else { Image(systemName: "arrow.up.to.line") Text("展开").font(.subheadline) } } } #if os(macOS) || os(tvOS) .buttonStyle(.plain) #endif Button { Task { await doURLTest() } } label: { Image(systemName: "bolt.fill") Text("测速").font(.subheadline) } #if os(macOS) || os(tvOS) .buttonStyle(.plain) #endif } .alertBinding($alert) .padding([.top, .bottom], 10) } public var body: some View { Section { if group.isExpand { LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: explandColumnCount())) { ForEach(group.items, id: \.tag) { it in GroupItemView($group, it) } } } else { VStack(spacing: 5) { ForEach(Array(itemGroups.enumerated()), id: \.offset) { items in HStack(spacing: 5) { ForEach(items.element, id: \.tag) { it in ZStack { Rectangle() .fill(it.delayColor) if it.tag == group.selected { Rectangle() .fill(Color.white) #if !os(tvOS) .frame(width: 5, height: 5) #else .frame(width: 15, height: 15) #endif } } #if !os(tvOS) .frame(width: 10, height: 10) #else .frame(width: 30, height: 30) #endif } }.frame(maxWidth: .infinity, alignment: .topLeading) } } } } header: { //title .frame(maxWidth: .infinity, alignment: .topLeading) } .background { /* GeometryReader { geometry in Rectangle() .fill(.clear) .frame(height: 1) .onChangeCompat(of: geometry.size.width) { newValue in geometryWidth = newValue } .onAppear { geometryWidth = geometry.size.width } }.padding() */ }.padding(.leading,-18.0) } private var itemGroups: [[OutboundGroupItem]] { let count: Int #if os(tvOS) count = Int(Int(geometryWidth) / 40) #else count = Int(Int(geometryWidth) / 20) #endif if count == 0 { return [group.items] } else { return group.items.chunked( into: count ) } } private func explandColumnCount() -> Int { let standardCount = Int(Int(geometryWidth) / 180) #if os(iOS) return standardCount < 2 ? 1 : standardCount #elseif os(tvOS) return 4 #else return standardCount < 1 ? 1 : standardCount #endif } private nonisolated func doURLTest() async { do { try await LibboxNewStandaloneCommandClient()!.urlTest(group.tag) } catch { await MainActor.run { alert = Alert(error) } } } private nonisolated func setGroupExpand() async { do { try await LibboxNewStandaloneCommandClient()!.setGroupExpand(group.tag, isExpand: group.isExpand) } catch { await MainActor.run { alert = Alert(error) } } } } private extension Array { func chunked(into size: Int) -> [[Element]] { stride(from: 0, to: count, by: size).map { Array(self[$0 ..< Swift.min($0 + size, count)]) } } }