Files
sing-box-for-apple/ApplicationLibrary/Views/Groups/GroupView.swift
T
2023-08-14 09:40:21 +08:00

153 lines
4.6 KiB
Swift

import Libbox
import Library
import SwiftUI
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(group.displayType)
.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.detached {
setGroupExpand()
}
} label: {
if group.isExpand {
Image(systemName: "arrow.down.to.line")
} else {
Image(systemName: "arrow.up.to.line")
}
}
#if os(macOS) || os(tvOS)
.buttonStyle(.plain)
#endif
Button {
Task.detached {
doURLTest()
}
} label: {
Image(systemName: "bolt.fill")
}
#if os(macOS) || os(tvOS)
.buttonStyle(.plain)
#endif
}
.alertBinding($alert)
.padding([.top, .bottom], 8)
}
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
Rectangle()
.fill(it.delayColor)
#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()
}
}
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 ? 2 : standardCount
#elseif os(tvOS)
return Int(Int(geometryWidth) / 400)
#else
return standardCount < 1 ? 1 : standardCount
#endif
}
private func doURLTest() {
do {
try LibboxNewStandaloneCommandClient()!.urlTest(group.tag)
} catch {
alert = Alert(error)
}
}
private func setGroupExpand() {
do {
try LibboxNewStandaloneCommandClient()!.setGroupExpand(group.tag, isExpand: group.isExpand)
} catch {
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)])
}
}
}