@@ -21,7 +21,7 @@ struct WidgetView: View {
2121 store. send ( . widgetClicked)
2222 }
2323 }
24- . overlay { overlayCircle }
24+ . overlay { WidgetAnimatedCircle ( store : store ) }
2525 . onHover { yes in
2626 withAnimation ( . easeInOut( duration: 0.2 ) ) {
2727 isHovering = yes
@@ -40,86 +40,101 @@ struct WidgetView: View {
4040 )
4141 }
4242 }
43+ }
44+
45+ struct WidgetAnimatedCircle : View {
46+ let store : StoreOf < CircularWidgetFeature >
47+ @State var processingProgress : Double = 0
4348
4449 struct OverlayCircleState : Equatable {
4550 var isProcessing : Bool
4651 var isContentEmpty : Bool
4752 }
4853
49- @ViewBuilder var overlayCircle : some View {
50- WithViewStore ( store, observe: { $0. animationProgress } ) { viewStore in
51- let processingProgress = viewStore. state
52- let minimumLineWidth : Double = 3
53- let lineWidth = ( 1 - processingProgress) *
54- ( Style . widgetWidth - minimumLineWidth / 2 ) + minimumLineWidth
55- let scale = max ( processingProgress * 1 , 0.0001 )
56- ZStack {
57- Circle ( )
58- . stroke (
59- Color ( nsColor: . darkGray) ,
60- style: . init( lineWidth: minimumLineWidth)
61- )
62- . padding ( minimumLineWidth / 2 )
54+ var body : some View {
55+ let minimumLineWidth : Double = 3
56+ let lineWidth = ( 1 - processingProgress) *
57+ ( Style . widgetWidth - minimumLineWidth / 2 ) + minimumLineWidth
58+ let scale = max ( processingProgress * 1 , 0.0001 )
59+ ZStack {
60+ Circle ( )
61+ . stroke (
62+ Color ( nsColor: . darkGray) ,
63+ style: . init( lineWidth: minimumLineWidth)
64+ )
65+ . padding ( minimumLineWidth / 2 )
6366
64- // how do I stop the repeatForever animation without removing the view?
65- // I tried many solutions found on stackoverflow but non of them works.
66- WithViewStore (
67- store,
68- observe: {
69- OverlayCircleState (
70- isProcessing: $0. isProcessing,
71- isContentEmpty: $0. isContentEmpty
72- )
73- }
74- ) { viewStore in
75- Group {
76- if viewStore. isProcessing {
77- Circle ( )
78- . stroke (
79- Color . accentColor,
80- style: . init( lineWidth: lineWidth)
81- )
82- . padding ( minimumLineWidth / 2 )
83- . scaleEffect ( x: scale, y: scale)
84- . opacity (
85- !viewStore. isContentEmpty || viewStore
86- . isProcessing ? 1 : 0
87- )
88- . animation (
89- featureFlag: \. animationCCrashSuggestion,
90- . easeInOut( duration: 1 )
91- . repeatForever ( autoreverses: true ) ,
92- value: processingProgress
93- )
94- } else {
95- Circle ( )
96- . stroke (
97- Color . accentColor,
98- style: . init( lineWidth: lineWidth)
99- )
100- . padding ( minimumLineWidth / 2 )
101- . scaleEffect ( x: scale, y: scale)
102- . opacity (
103- !viewStore. isContentEmpty || viewStore
104- . isProcessing ? 1 : 0
105- )
106- . animation (
107- featureFlag: \. animationCCrashSuggestion,
108- . easeInOut( duration: 1 ) ,
109- value: processingProgress
110- )
111- }
112- }
113- . onChange ( of: viewStore. isProcessing) { _ in
114- viewStore. send ( . _refreshRing)
115- }
116- . onChange ( of: viewStore. isContentEmpty) { _ in
117- viewStore. send ( . _refreshRing)
67+ // how do I stop the repeatForever animation without removing the view?
68+ // I tried many solutions found on stackoverflow but non of them works.
69+ WithViewStore (
70+ store,
71+ observe: {
72+ OverlayCircleState (
73+ isProcessing: $0. isProcessing,
74+ isContentEmpty: $0. isContentEmpty
75+ )
76+ }
77+ ) { viewStore in
78+ Group {
79+ if viewStore. isProcessing {
80+ Circle ( )
81+ . stroke (
82+ Color . accentColor,
83+ style: . init( lineWidth: lineWidth)
84+ )
85+ . padding ( minimumLineWidth / 2 )
86+ . scaleEffect ( x: scale, y: scale)
87+ . opacity (
88+ !viewStore. isContentEmpty || viewStore. isProcessing ? 1 : 0
89+ )
90+ . animation (
91+ featureFlag: \. animationCCrashSuggestion,
92+ . easeInOut( duration: 1 )
93+ . repeatForever ( autoreverses: true ) ,
94+ value: processingProgress
95+ )
96+ } else {
97+ Circle ( )
98+ . stroke (
99+ Color . accentColor,
100+ style: . init( lineWidth: lineWidth)
101+ )
102+ . padding ( minimumLineWidth / 2 )
103+ . scaleEffect ( x: scale, y: scale)
104+ . opacity (
105+ !viewStore. isContentEmpty || viewStore
106+ . isProcessing ? 1 : 0
107+ )
108+ . animation (
109+ featureFlag: \. animationCCrashSuggestion,
110+ . easeInOut( duration: 1 ) ,
111+ value: processingProgress
112+ )
118113 }
119114 }
115+ . onChange ( of: viewStore. isProcessing) { _ in
116+ refreshRing (
117+ isProcessing: viewStore. state. isProcessing,
118+ isContentEmpty: viewStore. state. isContentEmpty
119+ )
120+ }
121+ . onChange ( of: viewStore. isContentEmpty) { _ in
122+ refreshRing (
123+ isProcessing: viewStore. state. isProcessing,
124+ isContentEmpty: viewStore. state. isContentEmpty
125+ )
126+ }
120127 }
121128 }
122129 }
130+
131+ func refreshRing( isProcessing: Bool , isContentEmpty: Bool ) {
132+ if isProcessing {
133+ processingProgress = 1 - processingProgress
134+ } else {
135+ processingProgress = isContentEmpty ? 0 : 1
136+ }
137+ }
123138}
124139
125140struct WidgetContextMenu : View {
0 commit comments