@@ -15,8 +15,7 @@ class ProductTest {
1515}
1616
1717struct ProductsView : View {
18-
19- @State private var searchText = " "
18+
2019 @StateObject var viewModel = ProductsViewModel ( )
2120
2221 var body : some View {
@@ -28,11 +27,9 @@ struct ProductsView: View {
2827 . frame ( maxHeight: 1 )
2928 . navigationBarTitle ( " Products and Plans " , displayMode: . inline)
3029
31- VStack {
32- ProductListView ( )
33- }
34- . padding ( . top, 16 )
35- . background ( Color . white)
30+ ProductListView ( )
31+ . background ( Color . white)
32+ . searchable ( text: $viewModel. searchQuery, prompt: " Products and Plans " )
3633
3734 } . frame ( maxWidth: . infinity,
3835 maxHeight: . infinity,
@@ -42,42 +39,25 @@ struct ProductsView: View {
4239}
4340
4441extension ProductsView {
45-
46- @ViewBuilder
42+
4743 func ProductListView( ) -> some View {
4844 List {
49- ForEach ( viewModel. plyProducts , id: \. vendorId) { plyProduct in
45+ ForEach ( viewModel. searchResults , id: \. vendorId) { plyProduct in
5046 Section ( content: {
5147 PlansView ( plyProduct)
5248 } , header: {
5349 ProductTitleView ( plyProduct)
5450 } )
5551 }
56- } . listRowSpacing ( 10 )
57- . scrollContentBackground ( . hidden)
52+ }
53+ . listRowSpacing ( 10 )
54+ . scrollContentBackground ( . hidden)
5855 }
5956
60- @ViewBuilder
6157 func PlansView( _ plyProduct: SampleProductObject ) -> some View {
62- ForEach ( plyProduct. plans) { plan in
63- VStack ( alignment: . leading) {
64- Text ( plan. vendorId)
65- . bold ( )
66- Text ( plan. name)
67- Text ( plan. appleProductId)
68- Button {
69- UIPasteboard . general. string = plan. vendorId
70- } label: {
71- Image ( systemName: " doc.on.doc " )
72- . foregroundColor ( . white)
73- . padding ( . trailing)
74- }
75- }
76- . listRowBackground ( Color . mainLight)
77- }
58+ ForEach ( plyProduct. plans, content: PlanView . init ( plan: ) )
7859 }
7960
80- @ViewBuilder
8161 func ProductTitleView( _ plyProduct: SampleProductObject ) -> some View {
8262 HStack {
8363 VStack ( alignment: . leading) {
@@ -87,8 +67,8 @@ extension ProductsView {
8767
8868 Text ( plyProduct. vendorId)
8969 . font ( . body)
90- } . padding ( . trailing , 16 )
91-
70+ }
71+ Spacer ( )
9272 ZStack {
9373 Capsule ( )
9474 . frame ( width: 80 , height: 30 )
@@ -102,6 +82,77 @@ extension ProductsView {
10282 }
10383}
10484
85+ struct PlanView : View {
86+ @State var isExpanded : Bool = false
87+
88+ let plan : SamplePlanObject
89+
90+ init ( plan: SamplePlanObject ) {
91+ self . plan = plan
92+ }
93+
94+ var body : some View {
95+ VStack ( alignment: . leading) {
96+ HStack {
97+ Text ( plan. name)
98+ . font ( . headline)
99+ Spacer ( )
100+ Button {
101+ UIPasteboard . general. string = plan. vendorId
102+ } label: {
103+ Image ( systemName: " doc.on.doc " )
104+ . foregroundColor ( . white)
105+ . frame ( width: 35 , height: 35 )
106+ }
107+ . buttonStyle ( . plain)
108+ }
109+ HStack {
110+ VStack ( alignment: . leading) {
111+ Text ( plan. vendorId)
112+ Text ( plan. appleProductId)
113+ }
114+ . foregroundStyle ( . secondary)
115+ . fontWeight ( . semibold)
116+ Spacer ( )
117+ Button ( action: {
118+ isExpanded. toggle ( )
119+ } , label: {
120+ Image ( systemName: isExpanded ? " chevron.up " : " chevron.down " )
121+ . frame ( width: 35 , height: 35 )
122+ } )
123+ . buttonStyle ( . plain)
124+ . font ( . body)
125+ }
126+ if isExpanded {
127+ Spacer ( )
128+ . frame ( height: 20 )
129+ labelWithValue ( " localized price " , with: plan. plyPlan. localizedPrice ( ) )
130+ labelWithValue ( " localized full price " , with: plan. plyPlan. localizedFullPrice ( ) )
131+ labelWithValue ( " localized intro. price " , with: plan. plyPlan. localizedIntroductoryPrice ( ) )
132+ labelWithValue ( " localized full intro. price " , with: plan. plyPlan. localizedFullIntroductoryPrice ( ) )
133+ Divider ( )
134+ labelWithValue ( " intro. period " , with: plan. plyPlan. introductoryPeriod ( ) )
135+ labelWithValue ( " localized period " , with: plan. plyPlan. localizedPeriod ( ) )
136+ labelWithValue ( " localized intro. period " , with: plan. plyPlan. localizedIntroductoryPeriod ( ) )
137+ Divider ( )
138+ labelWithValue ( " duration " , with: plan. plyPlan. duration)
139+ labelWithValue ( " intro. duration " , with: plan. plyPlan. introductoryDuration ( ) )
140+ labelWithValue ( " localized intro. duration " , with: plan. plyPlan. localizedIntroductoryDuration ( ) )
141+ Divider ( )
142+ labelWithValue ( " amount " , with: plan. plyPlan. amount)
143+ labelWithValue ( " currency code " , with: plan. plyPlan. currencyCode)
144+ labelWithValue ( " currency symbol " , with: plan. plyPlan. currencySymbol)
145+ }
146+ }
147+ . font ( . subheadline)
148+ . listRowBackground ( Color . mainLight)
149+ }
150+
151+ func labelWithValue< T: CustomStringConvertible > ( _ string: String , with value: T ? ) -> Text {
152+ Text ( " \( string) : \( value? . description ?? " nil " ) " )
153+ }
154+ }
155+
105156#Preview {
106157 ProductsView ( )
107158}
0 commit comments