@@ -39,56 +39,74 @@ struct AboutView: View {
3939 }
4040
4141 var body : some View {
42- List {
43- VStack ( spacing: 8 ) {
44- if let url = appIconURL {
45- AsyncImage ( url: url) { phase in
46- if let img = phase. image {
47- img
48- . resizable ( )
49- . scaledToFit ( )
50- . frame ( width: 120 , height: 120 )
51- . clipShape ( RoundedRectangle ( cornerRadius: 20 , style: . continuous) )
52- . shadow ( radius: 6 )
53- } else if phase. error != nil {
54- Image ( systemName: " app.fill " )
55- . resizable ( )
56- . scaledToFit ( )
57- . frame ( width: 80 , height: 80 )
58- . foregroundColor ( . secondary)
59- } else {
60- ProgressView ( )
61- . frame ( width: 80 , height: 80 )
42+ NavigationView {
43+ List {
44+ VStack ( spacing: 12 ) {
45+ if let url = appIconURL {
46+ AsyncImage ( url: url) { phase in
47+ if let img = phase. image {
48+ img
49+ . resizable ( )
50+ . scaledToFit ( )
51+ . frame ( width: 120 , height: 120 )
52+ . clipShape ( RoundedRectangle ( cornerRadius: 24 , style: . continuous) )
53+ . shadow ( color: Color . black. opacity ( 0.2 ) , radius: 6 , x: 0 , y: 2 )
54+ . background (
55+ RoundedRectangle ( cornerRadius: 24 , style: . continuous)
56+ . fill ( Color . blue. opacity ( 0.1 ) ) // Subtle background
57+ )
58+ . padding ( 4 )
59+ } else if phase. error != nil {
60+ Image ( systemName: " app.fill " )
61+ . resizable ( )
62+ . scaledToFit ( )
63+ . frame ( width: 80 , height: 80 )
64+ . foregroundColor ( . blue. opacity ( 0.6 ) ) // Tinted fallback
65+ } else {
66+ ProgressView ( )
67+ . tint ( . blue) // Tinted spinner
68+ . frame ( width: 80 , height: 80 )
69+ }
6270 }
71+ . animation ( . easeIn( duration: 0.3 ) , value: url) // Fade-in animation
6372 }
64- }
6573
66- Text ( " ProStore " )
67- . font ( . title2)
68- . fontWeight ( . semibold)
74+ Text ( " ProStore " )
75+ . font ( . title2)
76+ . fontWeight ( . bold) // Bolder for emphasis
77+ . foregroundColor ( . primary)
6978
70- Text ( " Version \( versionString) " )
71- . font ( . footnote)
72- . foregroundColor ( . secondary)
73- }
74- . frame ( maxWidth: . infinity)
75- . padding ( . vertical, 20 )
76- . listRowInsets ( EdgeInsets ( ) )
79+ Text ( " Version \( versionString) " )
80+ . font ( . footnote)
81+ . foregroundColor ( . secondary)
82+ }
83+ . frame ( maxWidth: . infinity)
84+ . padding ( . vertical, 24 ) // More spacing
85+ . listRowInsets ( EdgeInsets ( ) )
86+ . background ( Color . blue. opacity ( 0.05 ) ) // Subtle list row background
7787
78- Section ( header: Text ( " Credits " ) ) {
79- ForEach ( credits) { c in
80- CreditRow ( credit: c)
88+ Section ( header: Text ( " Credits " )
89+ . font ( . headline)
90+ . foregroundColor ( . primary)
91+ . padding ( . top, 8 ) ) {
92+ ForEach ( credits) { c in
93+ CreditRow ( credit: c)
94+ }
8195 }
8296 }
97+ . listStyle ( . insetGrouped)
98+ . background ( Color ( UIColor . systemBackground) ) // Clean background
99+ . navigationTitle ( " About ProStore " )
100+ . navigationBarTitleDisplayMode ( . inline)
101+ . accentColor ( . blue) // Consistent blue accent
83102 }
84- . listStyle ( InsetGroupedListStyle ( ) )
85- . navigationTitle ( " About " )
86103 }
87104}
88105
89106struct CreditRow : View {
90107 let credit : Credit
91108 @Environment ( \. openURL) var openURL
109+ @State private var isTapped = false // For button animation
92110
93111 var body : some View {
94112 HStack ( spacing: 12 ) {
@@ -97,21 +115,31 @@ struct CreditRow: View {
97115 img
98116 . resizable ( )
99117 . scaledToFill ( )
118+ . frame ( width: 48 , height: 48 )
119+ . clipShape ( Circle ( ) )
120+ . overlay (
121+ Circle ( )
122+ . stroke ( Color . blue. opacity ( 0.3 ) , lineWidth: 1 ) // Modern border
123+ )
100124 } else if phase. error != nil {
101125 Image ( systemName: " person.crop.circle.fill " )
102126 . resizable ( )
103127 . scaledToFill ( )
128+ . frame ( width: 48 , height: 48 )
129+ . foregroundColor ( . blue. opacity ( 0.6 ) ) // Tinted fallback
104130 } else {
105131 ProgressView ( )
132+ . tint ( . blue) // Tinted spinner
133+ . frame ( width: 48 , height: 48 )
106134 }
107135 }
108- . frame ( width: 44 , height: 44 )
109- . clipShape ( Circle ( ) )
110- . overlay ( Circle ( ) . stroke ( Color ( UIColor . separator) , lineWidth: 0.5 ) )
136+ . animation ( . easeIn( duration: 0.3 ) , value: credit. avatarURL) // Fade-in animation
111137
112- VStack ( alignment: . leading, spacing: 2 ) {
138+ VStack ( alignment: . leading, spacing: 4 ) {
113139 Text ( credit. name)
114140 . font ( . body)
141+ . fontWeight ( . medium)
142+ . foregroundColor ( . primary)
115143 Text ( credit. role)
116144 . font ( . subheadline)
117145 . foregroundColor ( . secondary)
@@ -120,14 +148,29 @@ struct CreditRow: View {
120148 Spacer ( )
121149
122150 Button {
151+ isTapped = true
123152 openURL ( credit. profileURL)
153+ DispatchQueue . main. asyncAfter ( deadline: . now( ) + 0.2 ) {
154+ isTapped = false
155+ }
124156 } label: {
125157 Image ( systemName: " arrow.up.right.square " )
126158 . imageScale ( . large)
127- . foregroundColor ( . accentColor)
159+ . foregroundColor ( . blue)
160+ . padding ( 8 )
161+ . background ( Color . blue. opacity ( 0.1 ) ) // Subtle button background
162+ . clipShape ( Circle ( ) )
163+ . scaleEffect ( isTapped ? 0.9 : 1.0 ) // Tap animation
128164 }
129165 . buttonStyle ( BorderlessButtonStyle ( ) )
166+ . animation ( . easeInOut( duration: 0.2 ) , value: isTapped) // Smooth tap animation
130167 }
131168 . padding ( . vertical, 8 )
169+ . padding ( . horizontal, 8 )
170+ . background (
171+ RoundedRectangle ( cornerRadius: 12 )
172+ . fill ( Color . blue. opacity ( 0.05 ) ) // Subtle row background
173+ )
174+ . padding ( . horizontal, 4 )
132175 }
133176}
0 commit comments