@@ -12,99 +12,107 @@ import OSLog
1212struct RXTXIndicatorWidget : View {
1313 @EnvironmentObject var accessoryManager : AccessoryManager
1414 @State private var isPopoverOpen = false
15-
15+
1616 let fontSize : CGFloat = 7.0
1717 var body : some View {
18- Button ( action: {
19- if !isPopoverOpen && accessoryManager. isConnected {
20- Task {
21- // TODO: replace with a heartbeat when the heartbeat works
22- try await Task . sleep ( for: . seconds( 0.5 ) ) // little delay for user affordance
23- if accessoryManager. checkIsVersionSupported ( forVersion: " 2.7.4 " ) {
24- Logger . transport. debug ( " [RXTXIndicator] sending heartbeat (2.7.4+) " )
25- try await accessoryManager. sendHeartbeat ( )
26- } else {
27- Logger . transport. debug ( " [RXTXIndicator] sending metadata request (pre 2.7.4 does not support heartbeat nonce) " )
28- _ = try await accessoryManager. requestDeviceMetadata ( )
29- }
18+ Button (
19+ action: togglePopover,
20+ label: {
21+ VStack ( spacing: 3.0 ) {
22+ HStack ( spacing: 2.0 ) {
23+ Image ( systemName: " arrow.up " )
24+ . font ( . system( size: fontSize) )
25+ LEDIndicator ( flash: $accessoryManager. packetsSent, color: . green)
26+ } . frame ( maxHeight: fontSize)
27+ HStack ( spacing: 2.0 ) {
28+ Image ( systemName: " arrow.down " )
29+ . font ( . system( size: fontSize) )
30+ LEDIndicator ( flash: $accessoryManager. packetsReceived, color: . red)
31+ } . frame ( maxHeight: fontSize)
3032 }
31- }
32- #if targetEnvironment(macCatalyst)
33- if #available( macOS 26 . 0 , * ) {
34- // Don't show popover that crashes on mac 26
35- } else {
36- self . isPopoverOpen. toggle ( )
33+ . contentShape ( Rectangle ( ) ) // Make sure the whole thing is tappable
34+ . popover ( isPresented: self . $isPopoverOpen,
35+ attachmentAnchor: . rect( . bounds) ,
36+ arrowEdge: . top) {
37+ popoverEnabledView ( )
3738 }
38- #else
39- self . isPopoverOpen. toggle ( )
40- #endif
41-
42- } ) {
43- VStack ( spacing: 3.0 ) {
44- HStack ( spacing: 2.0 ) {
45- Image ( systemName: " arrow.up " )
46- . font ( . system( size: fontSize) )
47- LEDIndicator ( flash: $accessoryManager. packetsSent, color: . green)
48- } . frame ( maxHeight: fontSize)
49- HStack ( spacing: 2.0 ) {
50- Image ( systemName: " arrow.down " )
51- . font ( . system( size: fontSize) )
52- LEDIndicator ( flash: $accessoryManager. packetsReceived, color: . red)
53- } . frame ( maxHeight: fontSize)
5439 }
55- . contentShape ( Rectangle ( ) ) // Make sure the whole thing is tappable
56- . popover ( isPresented: self . $isPopoverOpen,
57- attachmentAnchor: . rect( . bounds) ,
58- arrowEdge: . top) {
59- Button ( action: {
60- self . isPopoverOpen = false
61- } ) {
62- VStack ( spacing: 0.5 ) {
63- Text ( " Packet Count " )
64- . font ( . caption)
65- . bold ( )
66- . padding ( 2.0 )
67- Divider ( )
68- VStack ( alignment: . leading) {
69- HStack ( spacing: 3.0 ) {
70- HStack ( spacing: 2.0 ) {
71- LEDIndicator ( flash: $accessoryManager. packetsSent, color: . green)
72- . frame ( maxHeight: fontSize)
73- Image ( systemName: " arrow.up " )
74- . font ( . system( size: fontSize) )
75- }
76- Text ( " To Radio (TX): \( accessoryManager. packetsSent) " )
77- . font ( . caption2)
78- Spacer ( )
40+ ) . buttonStyle ( . borderless)
41+ }
42+
43+ @ViewBuilder
44+ func popoverEnabledView( ) -> some View {
45+ Button (
46+ action: { self . isPopoverOpen = false } ,
47+ label: {
48+ VStack ( spacing: 0.5 ) {
49+ Text ( " Packet Count " )
50+ . font ( . caption)
51+ . bold ( )
52+ . padding ( 2.0 )
53+ Divider ( )
54+ VStack ( alignment: . leading) {
55+ HStack ( spacing: 3.0 ) {
56+ HStack ( spacing: 2.0 ) {
57+ LEDIndicator ( flash: $accessoryManager. packetsSent, color: . green)
58+ . frame ( maxHeight: fontSize)
59+ Image ( systemName: " arrow.up " )
60+ . font ( . system( size: fontSize) )
7961 }
80- HStack ( spacing : 3.0 ) {
81- HStack ( spacing : 2.0 ) {
82- LEDIndicator ( flash : $accessoryManager . packetsReceived , color : . red )
83- . frame ( maxHeight : fontSize )
84- Image ( systemName : " arrow.down " )
85- . font ( . system ( size : fontSize ) )
86- }
87- Text ( " From Radio (RX): \( accessoryManager . packetsReceived ) " )
88- . font ( . caption2 )
89- Spacer ( )
62+ Text ( " To Radio (TX): \( accessoryManager . packetsSent ) " )
63+ . font ( . caption2 )
64+ Spacer ( )
65+ }
66+ HStack ( spacing : 3.0 ) {
67+ HStack ( spacing : 2.0 ) {
68+ LEDIndicator ( flash : $accessoryManager . packetsReceived , color : . red )
69+ . frame ( maxHeight : fontSize )
70+ Image ( systemName : " arrow.down " )
71+ . font ( . system ( size : fontSize ) )
9072 }
91- } . padding ( 2.0 )
92- } . padding ( 10 )
93- . contentShape ( Rectangle ( ) ) // Make sure the whole thing is tappable
94- } . buttonStyle ( . plain)
95- . presentationCompactAdaptation ( . popover)
73+ Text ( " From Radio (RX): \( accessoryManager. packetsReceived) " )
74+ . font ( . caption2)
75+ Spacer ( )
76+ }
77+ } . padding ( 2.0 )
78+ } . padding ( 10 )
79+ . contentShape ( Rectangle ( ) ) // Make sure the whole thing is tappable
9680 }
97- } . buttonStyle ( . borderless)
81+ ) . buttonStyle ( . plain)
82+ . presentationCompactAdaptation ( . popover)
83+ }
84+
85+ func togglePopover( ) {
86+ if !isPopoverOpen && accessoryManager. isConnected {
87+ Task {
88+ // TODO: replace with a heartbeat when the heartbeat works
89+ try await Task . sleep ( for: . seconds( 0.5 ) ) // little delay for user affordance
90+ if accessoryManager. checkIsVersionSupported ( forVersion: " 2.7.4 " ) {
91+ Logger . transport. debug ( " [RXTXIndicator] sending heartbeat (2.7.4+) " )
92+ try await accessoryManager. sendHeartbeat ( )
93+ } else {
94+ Logger . transport. debug ( " [RXTXIndicator] sending metadata request (pre 2.7.4 does not support heartbeat nonce) " )
95+ _ = try await accessoryManager. requestDeviceMetadata ( )
96+ }
97+ }
98+ }
99+ #if targetEnvironment(macCatalyst)
100+ if #unavailable( macOS 26 . 0 ) {
101+ self . isPopoverOpen. toggle ( )
102+ }
103+ #else
104+ self . isPopoverOpen. toggle ( )
105+ #endif
98106 }
99107}
100108
101109struct LEDIndicator : View {
102110 @Environment ( \. colorScheme) var colorScheme
103111 @Binding var flash : Int
104112 let color : Color
105-
113+
106114 @State private var brightness : Double = 0.0
107-
115+
108116 var body : some View {
109117 Circle ( )
110118 . foregroundColor ( color. opacity ( brightness) )
0 commit comments