@@ -24,19 +24,61 @@ struct PeopleListScreen: View {
2424
2525 var body : some View {
2626 NavigationStack ( path: $path) {
27- VStack {
27+ ZStack {
28+ // Background color to match details screen
29+ Color ( . systemGroupedBackground)
30+ . edgesIgnoringSafeArea ( . all)
31+
2832 Observing ( viewModel. uiState) { playerListUIState in
2933 switch onEnum ( of: playerListUIState) {
3034 case . loading:
31- ProgressView ( )
32- . progressViewStyle ( CircularProgressViewStyle ( ) )
35+ VStack ( spacing: 16 ) {
36+ ProgressView ( )
37+ . progressViewStyle ( CircularProgressViewStyle ( ) )
38+ Text ( " Loading astronauts... " )
39+ . font ( . headline)
40+ . foregroundColor ( . secondary)
41+ }
3342 case . error( let error) :
34- Text ( " Error: \( error) " )
43+ VStack ( spacing: 16 ) {
44+ Image ( systemName: " exclamationmark.triangle " )
45+ . font ( . largeTitle)
46+ . foregroundColor ( . orange)
47+ Text ( " Error: \( error) " )
48+ . font ( . headline)
49+ . foregroundColor ( . primary)
50+ . multilineTextAlignment ( . center)
51+
52+ Button ( action: {
53+ // Refresh action
54+ viewModel = PersonListViewModel ( )
55+ } ) {
56+ Label ( " Try Again " , systemImage: " arrow.clockwise " )
57+ . padding ( )
58+ . background ( Color . blue)
59+ . foregroundColor ( . white)
60+ . cornerRadius ( 8 )
61+ }
62+ }
63+ . padding ( )
3564 case . success( let success) :
36- List ( success. result, id: \. name) { person in
37- NavigationLink ( value: person) {
38- PersonView ( person: person)
65+ ScrollView {
66+ LazyVStack ( spacing: 12 ) {
67+ ForEach ( success. result, id: \. name) { person in
68+ NavigationLink ( value: person) {
69+ PersonView ( person: person)
70+ . padding ( . horizontal)
71+ . background (
72+ RoundedRectangle ( cornerRadius: 12 )
73+ . fill ( Color ( . systemBackground) )
74+ . shadow ( color: Color . black. opacity ( 0.05 ) , radius: 5 , x: 0 , y: 2 )
75+ )
76+ . padding ( . horizontal)
77+ }
78+ . buttonStyle ( PlainButtonStyle ( ) )
79+ }
3980 }
81+ . padding ( . vertical)
4082 }
4183 }
4284 }
@@ -45,7 +87,17 @@ struct PeopleListScreen: View {
4587 PersonDetailsScreen ( person: person)
4688 }
4789 . navigationBarTitle ( Text ( " People In Space " ) )
48- . navigationBarTitleDisplayMode ( . inline)
90+ . navigationBarTitleDisplayMode ( . large)
91+ . toolbar {
92+ ToolbarItem ( placement: . navigationBarTrailing) {
93+ Button ( action: {
94+ // Refresh action
95+ viewModel = PersonListViewModel ( )
96+ } ) {
97+ Image ( systemName: " arrow.clockwise " )
98+ }
99+ }
100+ }
49101 }
50102 }
51103}
@@ -54,21 +106,52 @@ struct PersonView: View {
54106 let person : Assignment
55107
56108 var body : some View {
57- HStack {
109+ HStack ( spacing: 16 ) {
110+ // Person image with improved styling
58111 AsyncImage ( url: URL ( string: person. personImageUrl ?? " " ) ) { image in
59- image. resizable ( )
60- . aspectRatio ( contentMode: . fit)
112+ image. resizable ( )
113+ . aspectRatio ( contentMode: . fill)
114+ . clipShape ( Circle ( ) )
115+ . overlay ( Circle ( ) . stroke ( Color . gray. opacity ( 0.2 ) , lineWidth: 1 ) )
61116 } placeholder: {
62- ProgressView ( )
117+ Circle ( )
118+ . fill ( Color . gray. opacity ( 0.2 ) )
119+ . overlay (
120+ ProgressView ( )
121+ . progressViewStyle ( CircularProgressViewStyle ( tint: . gray) )
122+ )
63123 }
64- . frame ( width: 64 , height: 64 )
65-
124+ . frame ( width: 70 , height: 70 )
125+ . shadow ( color : . gray . opacity ( 0.3 ) , radius : 3 , x : 0 , y : 1 )
66126
67- VStack ( alignment: . leading) {
68- Text ( person. name) . font ( . headline)
69- Text ( person. craft) . font ( . subheadline)
127+ // Person information with improved typography and layout
128+ VStack ( alignment: . leading, spacing: 6 ) {
129+ Text ( person. name)
130+ . font ( . headline)
131+ . foregroundColor ( . primary)
132+
133+ Text ( person. craft)
134+ . font ( . subheadline)
135+ . foregroundColor ( . secondary)
136+
137+ // Add a subtle bio preview if available
138+ if let bio = person. personBio, !bio. isEmpty {
139+ Text ( bio. prefix ( 50 ) + ( bio. count > 50 ? " ... " : " " ) )
140+ . font ( . caption)
141+ . foregroundColor ( . secondary)
142+ . lineLimit ( 1 )
143+ }
70144 }
145+
146+ Spacer ( )
147+
148+ // Add a chevron to indicate navigation
149+ Image ( systemName: " chevron.right " )
150+ . font ( . caption)
151+ . foregroundColor ( . gray)
71152 }
153+ . padding ( . vertical, 8 )
154+ . contentShape ( Rectangle ( ) )
72155 }
73156}
74157
@@ -78,22 +161,131 @@ struct PersonDetailsScreen: View {
78161
79162 var body : some View {
80163 ScrollView {
81- VStack ( alignment: . center, spacing: 32 ) {
82- Text ( person. name) . font ( . title)
164+ VStack ( alignment: . center, spacing: 0 ) {
165+ // Header with astronaut name and craft
166+ VStack ( spacing: 8 ) {
167+ Text ( person. name)
168+ . font ( . largeTitle)
169+ . fontWeight ( . bold)
170+ . foregroundColor ( . primary)
171+ . multilineTextAlignment ( . center)
172+
173+ Text ( " Currently on \( person. craft) " )
174+ . font ( . headline)
175+ . foregroundColor ( . secondary)
176+ . padding ( . bottom, 16 )
177+ }
178+ . padding ( . top, 24 )
179+ . padding ( . horizontal)
83180
84- AsyncImage ( url: URL ( string: person. personImageUrl ?? " " ) ) { image in
85- image. resizable ( )
86- . aspectRatio ( contentMode: . fit)
87- } placeholder: {
88- ProgressView ( )
181+ // Astronaut image with enhanced styling
182+ ZStack {
183+ RoundedRectangle ( cornerRadius: 16 )
184+ . fill ( Color . gray. opacity ( 0.1 ) )
185+ . frame ( height: 300 )
186+
187+ AsyncImage ( url: URL ( string: person. personImageUrl ?? " " ) ) { image in
188+ image. resizable ( )
189+ . aspectRatio ( contentMode: . fit)
190+ . frame ( height: 300 )
191+ . clipShape ( RoundedRectangle ( cornerRadius: 16 ) )
192+ } placeholder: {
193+ VStack {
194+ ProgressView ( )
195+ . progressViewStyle ( CircularProgressViewStyle ( ) )
196+ Text ( " Loading image... " )
197+ . font ( . caption)
198+ . foregroundColor ( . secondary)
199+ . padding ( . top, 8 )
200+ }
201+ }
202+ . frame ( height: 300 )
89203 }
90- . frame ( width: 240 , height: 240 )
91-
92- Text ( person. personBio ?? " " ) . font ( . body)
93- Spacer ( )
204+ . padding ( . horizontal)
205+ . padding ( . bottom, 24 )
206+
207+ // Bio section with card styling
208+ if let bio = person. personBio, !bio. isEmpty {
209+ VStack ( alignment: . leading, spacing: 16 ) {
210+ Text ( " Biography " )
211+ . font ( . title2)
212+ . fontWeight ( . bold)
213+ . foregroundColor ( . primary)
214+
215+ Text ( bio)
216+ . font ( . body)
217+ . foregroundColor ( . primary)
218+ . fixedSize ( horizontal: false , vertical: true )
219+ . lineSpacing ( 6 )
220+ }
221+ . padding ( 24 )
222+ . background (
223+ RoundedRectangle ( cornerRadius: 16 )
224+ . fill ( Color ( . systemBackground) )
225+ . shadow ( color: Color . black. opacity ( 0.1 ) , radius: 10 , x: 0 , y: 5 )
226+ )
227+ . padding ( . horizontal)
228+ } else {
229+ VStack ( alignment: . center, spacing: 8 ) {
230+ Image ( systemName: " info.circle " )
231+ . font ( . largeTitle)
232+ . foregroundColor ( . secondary)
233+ Text ( " No biography available " )
234+ . font ( . headline)
235+ . foregroundColor ( . secondary)
236+ }
237+ . frame ( maxWidth: . infinity)
238+ . padding ( 24 )
239+ . background (
240+ RoundedRectangle ( cornerRadius: 16 )
241+ . fill ( Color . gray. opacity ( 0.1 ) )
242+ )
243+ . padding ( . horizontal)
244+ }
245+
246+ // Additional information section
247+ VStack ( alignment: . leading, spacing: 16 ) {
248+ Text ( " Additional Information " )
249+ . font ( . title2)
250+ . fontWeight ( . bold)
251+ . foregroundColor ( . primary)
252+
253+ HStack {
254+ VStack ( alignment: . leading, spacing: 8 ) {
255+ Label ( " Spacecraft " , systemImage: " airplane.circle.fill " )
256+ . font ( . headline)
257+ Text ( person. craft)
258+ . font ( . body)
259+ . foregroundColor ( . secondary)
260+ }
261+ . frame ( maxWidth: . infinity, alignment: . leading)
262+
263+ Divider ( )
264+ . frame ( height: 40 )
265+
266+ VStack ( alignment: . leading, spacing: 8 ) {
267+ Label ( " Mission " , systemImage: " star.circle.fill " )
268+ . font ( . headline)
269+ Text ( " Active " )
270+ . font ( . body)
271+ . foregroundColor ( . green)
272+ }
273+ . frame ( maxWidth: . infinity, alignment: . leading)
274+ }
275+ }
276+ . padding ( 24 )
277+ . background (
278+ RoundedRectangle ( cornerRadius: 16 )
279+ . fill ( Color ( . systemBackground) )
280+ . shadow ( color: Color . black. opacity ( 0.1 ) , radius: 10 , x: 0 , y: 5 )
281+ )
282+ . padding ( . horizontal)
283+ . padding ( . top, 16 )
284+ . padding ( . bottom, 32 )
94285 }
95- . padding ( )
96286 }
287+ . background ( Color ( . systemGroupedBackground) . edgesIgnoringSafeArea ( . all) )
288+ . navigationBarTitleDisplayMode ( . inline)
97289 }
98290}
99291
0 commit comments