Merge profile to dashboard

This commit is contained in:
世界
2025-11-26 22:25:52 +08:00
parent 4f0d1098e6
commit 264c37218c
27 changed files with 1590 additions and 306 deletions
@@ -0,0 +1,60 @@
import SwiftUI
@MainActor
public struct NavigationButtonsView: View {
public let showGroupsButton: Bool
public let showConnectionsButton: Bool
public let groupsCount: Int
public let connectionsCount: Int
public let onGroupsTap: () -> Void
public let onConnectionsTap: () -> Void
public init(
showGroupsButton: Bool,
showConnectionsButton: Bool,
groupsCount: Int,
connectionsCount: Int,
onGroupsTap: @escaping () -> Void,
onConnectionsTap: @escaping () -> Void
) {
self.showGroupsButton = showGroupsButton
self.showConnectionsButton = showConnectionsButton
self.groupsCount = groupsCount
self.connectionsCount = connectionsCount
self.onGroupsTap = onGroupsTap
self.onConnectionsTap = onConnectionsTap
}
public var body: some View {
HStack(spacing: 12) {
if showGroupsButton {
Divider()
Text(verbatim: "\(groupsCount)")
.font(.subheadline)
.foregroundStyle(.secondary)
.fixedSize()
Button {
onGroupsTap()
} label: {
Label("Groups", systemImage: "rectangle.3.group.fill")
}
.labelStyle(.iconOnly)
.foregroundStyle(.primary)
}
if showConnectionsButton {
Divider()
Text(verbatim: "\(connectionsCount)")
.font(.subheadline)
.foregroundStyle(.secondary)
.fixedSize()
Button {
onConnectionsTap()
} label: {
Label("Connections", systemImage: "list.bullet.rectangle.portrait.fill")
}
.labelStyle(.iconOnly)
.foregroundStyle(.primary)
}
}
}
}
@@ -0,0 +1,48 @@
import Library
import SwiftUI
@MainActor
public struct SheetContent<Content: View>: View {
private let title: String
private let content: Content
public init(_ title: String, @ViewBuilder content: () -> Content) {
self.title = title
self.content = content()
}
public var body: some View {
#if os(iOS) || os(tvOS)
NavigationStackCompat {
content
.navigationTitle(title)
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
}
.presentationDetentsIfAvailable()
#endif
}
}
@MainActor
public struct GroupsSheetContent: View {
public init() {}
public var body: some View {
SheetContent("Groups") {
GroupListView()
}
}
}
@MainActor
public struct ConnectionsSheetContent: View {
public init() {}
public var body: some View {
SheetContent("Connections") {
ConnectionListView()
}
}
}
@@ -58,6 +58,7 @@ public struct ShareButtonCompat<Label>: View where Label: View {
public var body: some View {
Button(action: shareItem, label: label)
.buttonStyle(.plain)
#if os(macOS)
.background(SharingServicePicker($sharePresented, $alert, itemURL))
#endif
@@ -66,7 +67,7 @@ public struct ShareButtonCompat<Label>: View where Label: View {
private func shareItem() {
#if os(iOS)
Task {
await shareItem0()
await shareItemAsync()
}
#elseif os(macOS)
sharePresented = true
@@ -74,11 +75,11 @@ public struct ShareButtonCompat<Label>: View where Label: View {
}
#if os(iOS)
private nonisolated func shareItem0() async {
private nonisolated func shareItemAsync() async {
do {
let shareItem = try await itemURL()
await MainActor.run {
shareItem1(shareItem)
presentShareController(shareItem)
}
} catch {
await MainActor.run {
@@ -87,10 +88,20 @@ public struct ShareButtonCompat<Label>: View where Label: View {
}
}
private func shareItem1(_ item: URL) {
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
windowScene.keyWindow?.rootViewController?.present(UIActivityViewController(activityItems: [item], applicationActivities: nil), animated: true, completion: nil)
private func presentShareController(_ item: URL) {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootViewController = windowScene.keyWindow?.rootViewController
else {
return
}
var topViewController = rootViewController
while let presented = topViewController.presentedViewController {
topViewController = presented
}
topViewController.present(
UIActivityViewController(activityItems: [item], applicationActivities: nil),
animated: true
)
}
#endif
}
@@ -0,0 +1,39 @@
import SwiftUI
public extension View {
@ViewBuilder
func presentationDetentsIfAvailable() -> some View {
#if os(iOS) || os(tvOS)
if #available(iOS 16.0, tvOS 17.0, *) {
self.presentationDetents([.large])
.presentationDragIndicator(.visible)
} else {
self
}
#else
self
#endif
}
#if os(iOS) || os(tvOS)
@available(iOS 16.0, tvOS 17.0, *)
@ViewBuilder
func presentationDetentsIfAvailable(_ detents: PresentationDetent...) -> some View {
let detentSet: Set<PresentationDetent> = detents.isEmpty ? [.large] : Set(detents)
presentationDetents(detentSet)
.presentationDragIndicator(.visible)
}
#endif
@ViewBuilder
func actionButtonStyle() -> some View {
if #available(iOS 26.0, macOS 26.0, tvOS 26.0, *) {
self.frame(width: 36, height: 36)
.glassEffect(.regular.interactive(), in: .circle)
} else {
frame(width: 36, height: 36)
.background(Color.secondary.opacity(0.1))
.clipShape(Circle())
}
}
}