@@ -6,16 +6,16 @@ public struct AppDetailView: View {
66 let app : AltApp
77 @StateObject private var downloadManager = DownloadSignManager ( )
88 @Environment ( \. dismiss) private var dismiss
9-
9+
1010 private var latestVersion : AppVersion ? {
1111 app. versions? . first
1212 }
13-
13+
1414 private func formatSize( _ size: Int ? ) -> String {
1515 guard let size = size else { return " Unknown " }
1616 return ByteCountFormatter . string ( fromByteCount: Int64 ( size) , countStyle: . file)
1717 }
18-
18+
1919 private func formatDate( _ dateString: String ? ) -> String {
2020 guard let dateString = dateString, let date = ISO8601DateFormatter ( ) . date ( from: dateString) else {
2121 return " Unknown "
@@ -24,17 +24,19 @@ public struct AppDetailView: View {
2424 formatter. dateStyle = . medium
2525 return formatter. string ( from: date)
2626 }
27-
27+
2828 public var body : some View {
2929 ZStack ( alignment: . bottom) {
3030 ScrollView {
3131 VStack ( alignment: . leading, spacing: 16 ) {
32+
3233 // App Header
3334 HStack ( alignment: . top, spacing: 16 ) {
3435 ZStack {
3536 RoundedRectangle ( cornerRadius: 12 )
3637 . fill ( Color . gray. opacity ( 0.12 ) )
3738 . frame ( width: 92 , height: 92 )
39+
3840 if let iconURL = app. iconURL {
3941 RetryAsyncImage (
4042 url: iconURL,
@@ -68,15 +70,18 @@ public struct AppDetailView: View {
6870 }
6971 }
7072 . frame ( width: 92 , height: 92 , alignment: . top)
73+
7174 VStack ( alignment: . leading, spacing: 4 ) {
7275 Text ( app. name)
7376 . font ( . title2)
7477 . bold ( )
78+
7579 if let dev = app. developerName, !dev. isEmpty {
7680 VStack ( alignment: . leading, spacing: 2 ) {
7781 Text ( dev)
7882 . font ( . subheadline)
7983 . foregroundColor ( . secondary)
84+
8085 if let repo = app. repositoryName, !repo. isEmpty {
8186 Text ( repo)
8287 . font ( . caption)
@@ -88,16 +93,19 @@ public struct AppDetailView: View {
8893 . font ( . subheadline)
8994 . foregroundColor ( . secondary)
9095 }
96+
9197 Text ( app. bundleIdentifier)
9298 . font ( . caption)
9399 . foregroundColor ( . secondary)
94100 . lineLimit ( 2 )
95101 }
96102 }
103+
97104 // General description
98105 if let generalDesc = app. localizedDescription, generalDesc != latestVersion? . localizedDescription {
99106 Text ( generalDesc)
100107 }
108+
101109 // What's New
102110 if let latest = latestVersion, let latestDesc = latest. localizedDescription,
103111 latestDesc != app. localizedDescription {
@@ -107,6 +115,7 @@ public struct AppDetailView: View {
107115 Text ( latestDesc)
108116 }
109117 }
118+
110119 // Version info
111120 if let latest = latestVersion {
112121 VStack ( alignment: . leading, spacing: 4 ) {
@@ -116,18 +125,21 @@ public struct AppDetailView: View {
116125 Text ( version)
117126 }
118127 }
128+
119129 if let dateString = latest. date, !dateString. isEmpty {
120130 HStack {
121131 Text ( " Released: " ) . bold ( )
122132 Text ( formatDate ( dateString) )
123133 }
124134 }
135+
125136 if let size = latest. size {
126137 HStack {
127138 Text ( " Size: " ) . bold ( )
128139 Text ( formatSize ( size) )
129140 }
130141 }
142+
131143 if let minOS = latest. minOSVersion, !minOS. isEmpty {
132144 HStack {
133145 Text ( " Min iOS Version: " ) . bold ( )
@@ -136,6 +148,7 @@ public struct AppDetailView: View {
136148 }
137149 }
138150 }
151+
139152 // Screenshots (from general app)
140153 if let screenshots = app. screenshotURLs, !screenshots. isEmpty {
141154 ScrollView ( . horizontal, showsIndicators: false ) {
@@ -172,38 +185,15 @@ public struct AppDetailView: View {
172185 . padding ( . vertical, 6 )
173186 }
174187 }
188+
175189 Spacer ( minLength: 80 ) // Space for the progress bar
176190 }
177191 . frame ( maxWidth: . infinity, alignment: . leading)
178192 . padding ( )
179193 }
180-
181- // Separate Error Banner (appears at the top of the screen)
182- if let errorMessage = downloadManager. errorMessage {
183- VStack ( spacing: 0 ) {
184- HStack {
185- Image ( systemName: " exclamationmark.triangle.fill " )
186- . foregroundColor ( . red)
187- Text ( errorMessage)
188- . font ( . caption)
189- . foregroundColor ( . primary)
190- Spacer ( )
191- }
192- . padding ( )
193- . background ( . regularMaterial)
194- . cornerRadius ( 10 )
195- . shadow ( radius: 4 )
196- . padding ( . horizontal)
197- . transition ( . move( edge: . top) )
198-
199- Spacer ( )
200- }
201- . zIndex ( 1 )
202- . animation ( . easeInOut( duration: 0.3 ) , value: downloadManager. errorMessage)
203- }
204-
194+
205195 // Floating Download Button
206- if !downloadManager. isProcessing && downloadManager . errorMessage == nil {
196+ if !downloadManager. isProcessing {
207197 VStack {
208198 Spacer ( )
209199 HStack {
@@ -228,20 +218,20 @@ public struct AppDetailView: View {
228218 }
229219 }
230220 }
231-
232- // Progress Bar (only during real download/signing/install process )
221+
222+ // Progress Bar (fixed at bottom, not part of scroll )
233223 if downloadManager. isProcessing {
234224 VStack ( spacing: 0 ) {
235225 Rectangle ( )
236226 . fill ( Color . gray. opacity ( 0.1 ) )
237227 . frame ( height: 1 )
238-
228+
239229 VStack ( spacing: 8 ) {
240230 HStack {
241231 ProgressView ( value: downloadManager. progress, total: 1.0 )
242232 . progressViewStyle ( LinearProgressViewStyle ( tint: downloadManager. showSuccess ? . green : . blue) )
243233 . scaleEffect ( x: 1 , y: 1.5 , anchor: . center)
244-
234+
245235 if downloadManager. showSuccess {
246236 Image ( systemName: " checkmark.circle.fill " )
247237 . foregroundColor ( . green)
@@ -253,16 +243,16 @@ public struct AppDetailView: View {
253243 . frame ( width: 40 )
254244 }
255245 }
256-
246+
257247 HStack {
258248 Text ( downloadManager. status)
259249 . font ( . caption)
260250 . foregroundColor ( downloadManager. showSuccess ? . green : . secondary)
261251 . lineLimit ( 1 )
262252 . truncationMode ( . middle)
263-
253+
264254 Spacer ( )
265-
255+
266256 if !downloadManager. showSuccess {
267257 Button ( " Cancel " ) {
268258 downloadManager. cancel ( )
@@ -288,7 +278,7 @@ public struct AppDetailView: View {
288278 downloadManager. cancel ( )
289279 }
290280 . foregroundColor ( . red)
291- } else if app. downloadURL != nil && downloadManager . errorMessage == nil {
281+ } else if app. downloadURL != nil {
292282 Button ( action: {
293283 downloadManager. downloadAndSign ( app: app)
294284 } ) {
@@ -302,6 +292,5 @@ public struct AppDetailView: View {
302292 }
303293 . animation ( . easeInOut( duration: 0.3 ) , value: downloadManager. isProcessing)
304294 . animation ( . easeInOut( duration: 0.3 ) , value: downloadManager. showSuccess)
305- . animation ( . easeInOut( duration: 0.3 ) , value: downloadManager. errorMessage)
306295 }
307296}
0 commit comments