@@ -6,7 +6,11 @@ import SwiftUI
66import LucidBanner
77
88@MainActor
9- func showHudBanner( scene: UIWindowScene ? , title: String ? = nil , subtitle: String ? = nil , onTap: ( ( _ token: Int ? , _ stage: String ? ) -> Void ) ? = nil ) -> Int ? {
9+ func showHudBanner( scene: UIWindowScene ? ,
10+ title: String ? = nil ,
11+ subtitle: String ? = nil ,
12+ stage: LucidBanner . Stage ? = nil ,
13+ onButtonTap: ( ( ) -> Void ) ? = nil ) -> Int ? {
1014 var scene = scene
1115 if scene == nil {
1216 scene = UIApplication . shared. mainAppWindow? . windowScene
@@ -18,11 +22,9 @@ func showHudBanner(scene: UIWindowScene?, title: String? = nil, subtitle: String
1822 subtitle: subtitle,
1923 vPosition: . center,
2024 blocksTouches: true ,
21- onTap: { token, stage in
22- onTap ? ( token, stage)
23- }
25+ stage: stage
2426 ) { state in
25- HudBannerView ( state: state)
27+ HudBannerView ( state: state, onButtonTap : onButtonTap )
2628 }
2729}
2830
@@ -56,16 +58,25 @@ struct HudBannerView: View {
5658 @ObservedObject var state : LucidBannerState
5759 @State private var displayedProgress : Double = 0
5860
61+ let onButtonTap : ( ( ) -> Void ) ?
62+
63+ private let textColor = Color ( . label)
5964 private let circleSize : CGFloat = 90
6065 private let lineWidth : CGFloat = 8
6166
67+ init ( state: LucidBannerState ,
68+ onButtonTap: ( ( ) -> Void ) ? = nil ) {
69+ self . state = state
70+ self . onButtonTap = onButtonTap
71+ }
72+
6273 var body : some View {
6374 let rawProgress = state. progress ?? 0
6475 let clampedProgress = min ( max ( rawProgress, 0 ) , 1 )
6576
66- let stage = state. stage ? . lowercased ( )
67- let isSuccess = ( stage == " success " )
68- let isError = ( stage == " error " )
77+ let isSuccess = ( state. typedStage == . success )
78+ let isError = ( state . typedStage == . error )
79+ let isButton = ( state . typedStage == . button )
6980
7081 let visualProgress : Double = {
7182 if isSuccess || isError {
@@ -88,15 +99,15 @@ struct HudBannerView: View {
8899 if let title = state. title, !title. isEmpty {
89100 Text ( title)
90101 . font ( . headline. weight ( . semibold) )
91- . foregroundStyle ( . primary )
102+ . foregroundStyle ( textColor )
92103 . multilineTextAlignment ( . center)
93104 }
94105
95106 // SUBTITLE
96107 if let subtitle = state. subtitle, !subtitle. isEmpty {
97108 Text ( subtitle)
98109 . font ( . subheadline)
99- . foregroundStyle ( . primary . opacity ( 0.95 ) )
110+ . foregroundStyle ( textColor )
100111 . multilineTextAlignment ( . center)
101112 }
102113
@@ -121,9 +132,6 @@ struct HudBannerView: View {
121132 . frame ( width: circleSize, height: circleSize)
122133
123134 // Center content:
124- // - checkmark for success
125- // - xmark for error
126- // - percentage for normal progress
127135 Group {
128136 if isSuccess {
129137 Image ( systemName: " checkmark " )
@@ -136,11 +144,26 @@ struct HudBannerView: View {
136144 } else {
137145 Text ( " \( Int ( visualProgress * 100 ) ) % " )
138146 . font ( . headline. monospacedDigit ( ) )
139- . foregroundStyle ( . primary )
147+ . foregroundStyle ( textColor )
140148 }
141149 }
142150 }
143151 . padding ( . top, 4 )
152+
153+ if isButton {
154+ VStack {
155+ Button ( " _cancel_ " ) {
156+ onButtonTap ? ( )
157+ }
158+ . buttonStyle ( . plain)
159+ . padding ( . horizontal, 20 )
160+ . padding ( . vertical, 10 )
161+ . background (
162+ Capsule ( )
163+ . stroke ( . gray, lineWidth: 1 )
164+ )
165+ }
166+ }
144167 }
145168 . padding ( . horizontal, 22 )
146169 . padding ( . vertical, 24 )
@@ -189,14 +212,22 @@ struct HudBannerView: View {
189212
190213 @ViewBuilder
191214 func containerView< Content: View > ( @ViewBuilder _ content: ( ) -> Content ) -> some View {
215+ let cornerRadius : CGFloat = 22
216+ let opacity = 0.65
217+ let backgroundColor = Color ( . systemBackground) . opacity ( 0.65 )
218+
192219 if #available( iOS 26 , * ) {
193220 content ( )
194- . glassEffect ( . regular, in: RoundedRectangle ( cornerRadius: 22 ) )
221+ . background (
222+ RoundedRectangle ( cornerRadius: cornerRadius)
223+ . fill ( backgroundColor)
224+ )
225+ . glassEffect ( . clear, in: RoundedRectangle ( cornerRadius: cornerRadius) )
195226 } else {
196227 content ( )
197- . background ( . ultraThinMaterial, in: RoundedRectangle ( cornerRadius: 22.0 ) )
228+ . background ( . ultraThinMaterial, in: RoundedRectangle ( cornerRadius: cornerRadius ) )
198229 . overlay (
199- RoundedRectangle ( cornerRadius: 22 , style: . continuous)
230+ RoundedRectangle ( cornerRadius: cornerRadius , style: . continuous)
200231 . stroke ( . white. opacity ( 0.9 ) , lineWidth: 0.6 )
201232 )
202233 . shadow ( color: . black. opacity ( 0.5 ) , radius: 10 , x: 0 , y: 4 )
@@ -208,6 +239,15 @@ struct HudBannerView: View {
208239
209240#Preview( " HudBannerView " ) {
210241 ZStack {
242+ Text (
243+ Array ( 0 ... 500 )
244+ . map ( String . init)
245+ . joined ( separator: " " )
246+ )
247+ . font ( . system( size: 16 , design: . monospaced) )
248+ . foregroundStyle ( . primary)
249+ . padding ( )
250+
211251 HudBannerPreviewWrapper ( )
212252 }
213253}
@@ -217,7 +257,8 @@ private struct HudBannerPreviewWrapper: View {
217257 title: " Uploading files " ,
218258 subtitle: " Syncing your library… " ,
219259 footnote: nil ,
220- imageAnimation: . none
260+ imageAnimation: . none,
261+ stage: " button "
221262 )
222263
223264 var body : some View {
0 commit comments