@@ -5,21 +5,41 @@ import StoreKit
5
5
import PocketCastsUtils
6
6
7
7
struct NowPlayingView : View {
8
+
9
+ enum ScreenState : Int {
10
+ case loading
11
+ case ready
12
+ case failed
13
+ }
14
+
8
15
@State var presentAppStoreOverlay : Bool = false
16
+ @State var state : ScreenState = . loading
9
17
10
18
var body : some View {
11
19
VStack {
12
- NowPlayingPlayerItemViewControllerRepresentable ( )
13
- . onAppear {
14
- DispatchQueue . main. asyncAfter ( deadline: . now( ) + 10 ) {
15
- presentAppStoreOverlay = true
20
+ Spacer ( )
21
+ HStack { Spacer ( ) }
22
+ switch state {
23
+ case . loading:
24
+ ProgressView ( )
25
+ . progressViewStyle ( . circular)
26
+ . tint ( UIColor . label. color)
27
+ case . ready:
28
+ NowPlayingPlayerItemViewControllerRepresentable ( )
29
+ . onAppear {
30
+ DispatchQueue . main. asyncAfter ( deadline: . now( ) + 10 ) {
31
+ presentAppStoreOverlay = true
32
+ }
16
33
}
17
- }
34
+ case . failed:
35
+ EmptyView ( )
36
+ }
37
+ Spacer ( )
18
38
}
39
+ . background ( state != . ready ? UIColor . systemBackground. color : PlayerColorHelper . playerBackgroundColor01 ( ) . color)
19
40
. appStoreOverlay ( isPresented: $presentAppStoreOverlay, configuration: {
20
41
SKOverlay . AppClipConfiguration ( position: . bottom)
21
42
} )
22
- . background ( Color ( uiColor: PlayerColorHelper . playerBackgroundColor01 ( ) ) )
23
43
. onContinueUserActivity ( NSUserActivityTypeBrowsingWeb) { userActivity in
24
44
handle ( userActivity: userActivity)
25
45
}
@@ -32,7 +52,10 @@ struct NowPlayingView: View {
32
52
let path = components. path,
33
53
path != " /get " ,
34
54
path != " /get/ "
35
- else { return }
55
+ else {
56
+ showErrorMessage ( userActivity: userActivity)
57
+ return
58
+ }
36
59
37
60
// NOTE: This doesn't handle the redeem URL. See `AppDelegate.handleContinue(_ userActivity: NSUserActivity)` for this logic
38
61
@@ -46,46 +69,63 @@ struct NowPlayingView: View {
46
69
PodcastManager . shared. importSharedItemFromUrl ( importPath) { shareItem in
47
70
guard let shareItem else {
48
71
FileLog . shared. addMessage ( " App Clip: Missing Share Item " )
72
+ showErrorMessage ( userActivity: userActivity)
49
73
return
50
74
}
51
75
52
76
guard let episodeUUID = shareItem. episodeHeader? . uuid else {
53
77
FileLog . shared. addMessage ( " App Clip: No episode found in share item " )
78
+ showErrorMessage ( userActivity: userActivity)
54
79
return
55
80
}
56
81
57
82
guard let podcastUUID = shareItem. podcastHeader? . uuid else {
58
83
FileLog . shared. addMessage ( " App Clip: No podcast found in share item " )
84
+ showErrorMessage ( userActivity: userActivity)
59
85
return
60
86
}
61
87
62
88
63
89
loadEpisode ( episodeUuid: episodeUUID, podcastUuid: podcastUUID) {
64
90
guard let episode = DataManager . sharedManager. findEpisode ( uuid: episodeUUID) else {
65
91
FileLog . shared. addMessage ( " App Clip: Could not find Episode " )
92
+ showErrorMessage ( userActivity: userActivity)
66
93
return
67
94
}
68
95
69
96
FileLog . shared. addMessage ( " App Clip: Loaded episode: \( episode. title ?? " unknown " ) " )
70
-
97
+ state = . ready
71
98
PlaybackManager . shared. load ( episode: episode, autoPlay: true , overrideUpNext: false )
72
99
Analytics . track ( . playbackPlay, source: AnalyticsSource . handleUserActivity, properties: [ " url " : incomingURL. absoluteString, " podcast " : podcastUUID, " episode " : episode. uuid] )
73
100
}
74
101
}
75
102
}
76
103
104
+ private func showErrorMessage( userActivity: NSUserActivity ) {
105
+ userActivity. invalidate ( )
106
+ state = . failed
107
+ DispatchQueue . main. async {
108
+ let rootViewController = ( UIApplication . shared. connectedScenes. first as? UIWindowScene ) ? . windows. first? . rootViewController
109
+ SJUIUtils . showAlert ( title: L10n . podcastShareErrorTitle, message: L10n . podcastShareErrorMsg, from: rootViewController)
110
+ }
111
+ }
112
+
77
113
private func loadEpisode( episodeUuid: String , podcastUuid: String , timestamp: TimeInterval ? = nil , completion: @escaping ( ) -> Void ) {
78
114
if let podcast = DataManager . sharedManager. findPodcast ( uuid: podcastUuid, includeUnsubscribed: true ) {
79
115
ServerPodcastManager . shared. updatePodcastIfRequired ( podcast: podcast) { _ in
80
- completion ( )
116
+ DispatchQueue . main. async {
117
+ completion ( )
118
+ }
81
119
}
82
120
83
121
return
84
122
}
85
123
86
124
ServerPodcastManager . shared. addFromUuid ( podcastUuid: podcastUuid, subscribe: false , completion: { success in
87
125
if success, let _ = DataManager . sharedManager. findPodcast ( uuid: podcastUuid, includeUnsubscribed: true ) {
88
- completion ( )
126
+ DispatchQueue . main. async {
127
+ completion ( )
128
+ }
89
129
} else {
90
130
DispatchQueue . main. async {
91
131
let rootViewController = ( UIApplication . shared. connectedScenes. first as? UIWindowScene ) ? . windows. first? . rootViewController
0 commit comments