1- import Environment
2- import Preferences
1+ import Foundation
32import SwiftUI
43
54@MainActor
6- final class SuggestionPanelViewModel : ObservableObject {
7- enum Content {
8- case suggestion( SuggestionProvider )
9- case promptToCode( PromptToCodeProvider )
10- case error( String )
11-
12- var contentHash : String {
13- switch self {
14- case let . error( e) :
15- return " error: \( e) "
16- case let . suggestion( provider) :
17- return " suggestion: \( provider. code. hashValue) "
18- case let . promptToCode( provider) :
19- return " provider: \( provider. id) "
20- }
21- }
22- }
23-
24- @Published var content : Content ?
25- @Published var isPanelDisplayed : Bool
5+ final class SuggestionPanelDisplayController : ObservableObject {
266 @Published var alignTopToAnchor = false
27- @Published var colorScheme : ColorScheme
7+ @Published var isPanelDisplayed : Bool = false
288
29- public init (
30- content: Content ? = nil ,
31- isPanelDisplayed: Bool = false ,
32- colorScheme: ColorScheme = . dark
9+ init (
10+ alignTopToAnchor: Bool = false ,
11+ isPanelDisplayed: Bool = false
3312 ) {
34- self . content = content
13+ self . alignTopToAnchor = alignTopToAnchor
3514 self . isPanelDisplayed = isPanelDisplayed
36- self . colorScheme = colorScheme
37- }
38- }
39-
40- extension View {
41- @ViewBuilder
42- func animation< V: Equatable > (
43- featureFlag: KeyPath < UserDefaultPreferenceKeys , FeatureFlag > ,
44- _ animation: Animation ? ,
45- value: V
46- ) -> some View {
47- let isOn = UserDefaults . shared. value ( for: featureFlag)
48- if isOn {
49- self . animation ( animation, value: value)
50- } else {
51- self
52- }
5315 }
5416}
5517
5618struct SuggestionPanelView : View {
57- @ObservedObject var viewModel : SuggestionPanelViewModel
19+ @ObservedObject var viewModel : SharedPanelViewModel
20+ @ObservedObject var displayController : SuggestionPanelDisplayController
21+ @AppStorage ( \. suggestionPresentationMode) var suggestionPresentationMode
5822
5923 var body : some View {
6024 VStack ( spacing: 0 ) {
61- if !viewModel . alignTopToAnchor {
25+ if !displayController . alignTopToAnchor {
6226 Spacer ( )
6327 . frame ( minHeight: 0 , maxHeight: . infinity)
6428 . allowsHitTesting ( false )
@@ -69,29 +33,32 @@ struct SuggestionPanelView: View {
6933 ZStack ( alignment: . topLeading) {
7034 switch content {
7135 case let . suggestion( suggestion) :
72- CodeBlockSuggestionPanel ( suggestion: suggestion)
73- case let . promptToCode( provider) :
74- PromptToCodePanel ( provider: provider)
75- case let . error( description) :
76- ErrorPanel ( viewModel: viewModel, description: description)
36+ switch suggestionPresentationMode {
37+ case . nearbyTextCursor:
38+ CodeBlockSuggestionPanel ( suggestion: suggestion)
39+ case . floatingWidget:
40+ EmptyView ( )
41+ }
42+ default :
43+ EmptyView ( )
7744 }
7845 }
79- . frame ( maxWidth: . infinity, maxHeight: Style . panelHeight )
46+ . frame ( maxWidth: . infinity, maxHeight: Style . inlineSuggestionMaxHeight )
8047 . fixedSize ( horizontal: false , vertical: true )
81- . allowsHitTesting ( viewModel . isPanelDisplayed)
48+ . allowsHitTesting ( displayController . isPanelDisplayed)
8249 }
8350 }
8451 . frame ( maxWidth: . infinity)
8552
86- if viewModel . alignTopToAnchor {
53+ if displayController . alignTopToAnchor {
8754 Spacer ( )
8855 . frame ( minHeight: 0 , maxHeight: . infinity)
8956 . allowsHitTesting ( false )
9057 }
9158 }
9259 . preferredColorScheme ( viewModel. colorScheme)
9360 . opacity ( {
94- guard viewModel . isPanelDisplayed else { return 0 }
61+ guard displayController . isPanelDisplayed else { return 0 }
9562 guard viewModel. content != nil else { return 0 }
9663 return 1
9764 } ( ) )
@@ -103,69 +70,8 @@ struct SuggestionPanelView: View {
10370 . animation (
10471 featureFlag: \. animationBCrashSuggestion,
10572 . easeInOut( duration: 0.2 ) ,
106- value: viewModel . isPanelDisplayed
73+ value: displayController . isPanelDisplayed
10774 )
108- . frame ( maxWidth: Style . panelWidth , maxHeight: Style . panelHeight )
75+ . frame ( maxWidth: Style . inlineSuggestionMinWidth , maxHeight: Style . inlineSuggestionMaxHeight )
10976 }
11077}
111-
112- struct CommandButtonStyle : ButtonStyle {
113- let color : Color
114-
115- func makeBody( configuration: Configuration ) -> some View {
116- configuration. label
117- . padding ( . vertical, 4 )
118- . padding ( . horizontal, 8 )
119- . foregroundColor ( . white)
120- . background (
121- RoundedRectangle ( cornerRadius: 4 , style: . continuous)
122- . fill ( color. opacity ( configuration. isPressed ? 0.8 : 1 ) )
123- . animation ( . easeOut( duration: 0.1 ) , value: configuration. isPressed)
124- )
125- . overlay {
126- RoundedRectangle ( cornerRadius: 4 , style: . continuous)
127- . stroke ( Color . white. opacity ( 0.2 ) , style: . init( lineWidth: 1 ) )
128- }
129- }
130- }
131-
132- // MARK: - Previews
133-
134- struct SuggestionPanelView_Error_Preview : PreviewProvider {
135- static var previews : some View {
136- SuggestionPanelView ( viewModel: . init(
137- content: . error( " This is an error \n error " ) ,
138- isPanelDisplayed: true
139- ) )
140- . frame ( width: 450 , height: 200 )
141- }
142- }
143-
144- struct SuggestionPanelView_Both_DisplayingSuggestion_Preview : PreviewProvider {
145- static var previews : some View {
146- SuggestionPanelView ( viewModel: . init(
147- content: . suggestion( SuggestionProvider (
148- code: """
149- - (void)addSubview:(UIView *)view {
150- [self addSubview:view];
151- }
152- """ ,
153- language: " objective-c " ,
154- startLineIndex: 8 ,
155- suggestionCount: 2 ,
156- currentSuggestionIndex: 0
157- ) ) ,
158- isPanelDisplayed: true ,
159- colorScheme: . dark
160- ) )
161- . frame ( width: 450 , height: 200 )
162- . background {
163- HStack {
164- Color . red
165- Color . green
166- Color . blue
167- }
168- }
169- }
170- }
171-
0 commit comments