Skip to content
This repository was archived by the owner on Jan 14, 2024. It is now read-only.

Commit b2741e4

Browse files
authored
Merge pull request #17 from conath/14-store-trailers-list-offline
Store movie trailer list and poster images offline
2 parents e0eefc8 + 4b7d973 commit b2741e4

19 files changed

+321
-143
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,5 @@ fastlane/test_output
8888
# https://github.com/johnno1962/injectionforxcode
8989

9090
iOSInjectionProject/
91+
92+
Secrets.swift

TheatricalMovieTrailers.xcodeproj/project.pbxproj

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
830005592541B1050069A8D1 /* MovieInfoDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830005582541B1050069A8D1 /* MovieInfoDataStore.swift */; };
11+
8300055D2541B34A0069A8D1 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8300055C2541B34A0069A8D1 /* Secrets.swift */; };
12+
830005602541C58E0069A8D1 /* AppError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8300055F2541C58E0069A8D1 /* AppError.swift */; };
1013
830AA4192536FB94006A3AEB /* TrailerPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 830AA4182536FB94006A3AEB /* TrailerPlayerView.swift */; };
1114
8316E0E424A64AD300467F14 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8316E0E324A64AD300467F14 /* AppDelegate.swift */; };
1215
8316E0E624A64AD300467F14 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8316E0E524A64AD300467F14 /* SceneDelegate.swift */; };
@@ -44,6 +47,9 @@
4447
/* End PBXBuildFile section */
4548

4649
/* Begin PBXFileReference section */
50+
830005582541B1050069A8D1 /* MovieInfoDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MovieInfoDataStore.swift; sourceTree = "<group>"; };
51+
8300055C2541B34A0069A8D1 /* Secrets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Secrets.swift; sourceTree = "<group>"; };
52+
8300055F2541C58E0069A8D1 /* AppError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppError.swift; sourceTree = "<group>"; };
4753
830AA4182536FB94006A3AEB /* TrailerPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrailerPlayerView.swift; sourceTree = "<group>"; };
4854
8316E0E024A64AD300467F14 /* TheatricalMovieTrailers.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TheatricalMovieTrailers.app; sourceTree = BUILT_PRODUCTS_DIR; };
4955
8316E0E324A64AD300467F14 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -145,6 +151,7 @@
145151
8316E0FD24A64B6900467F14 /* Undefined.swift */,
146152
8316E0EE24A64AD400467F14 /* LaunchScreen.storyboard */,
147153
8316E0E924A64AD400467F14 /* Assets.xcassets */,
154+
8300055C2541B34A0069A8D1 /* Secrets.swift */,
148155
);
149156
path = "Supporting Files";
150157
sourceTree = "<group>";
@@ -155,6 +162,8 @@
155162
8316E0FB24A64B5E00467F14 /* MovieInfo.swift */,
156163
831CD8F424ABE34A008EDC6F /* Settings.swift */,
157164
83D21173253F9CDD00EF54A3 /* SortingMode.swift */,
165+
830005582541B1050069A8D1 /* MovieInfoDataStore.swift */,
166+
8300055F2541C58E0069A8D1 /* AppError.swift */,
158167
);
159168
path = Model;
160169
sourceTree = "<group>";
@@ -261,11 +270,14 @@
261270
83F59A45253DCAFD00EEA7A5 /* CoverFlowScrollView.swift in Sources */,
262271
83D5252924A661760086707E /* MovieMetaView.swift in Sources */,
263272
8316E10224A64CD500467F14 /* ExternalTrailerView.swift in Sources */,
273+
830005602541C58E0069A8D1 /* AppError.swift in Sources */,
264274
8316E0E424A64AD300467F14 /* AppDelegate.swift in Sources */,
265275
8316E0FC24A64B5E00467F14 /* MovieInfo.swift in Sources */,
276+
830005592541B1050069A8D1 /* MovieInfoDataStore.swift in Sources */,
266277
83CBE5122537600F00E22FAE /* CoverFlowListView.swift in Sources */,
267278
8316E0FE24A64B6900467F14 /* Undefined.swift in Sources */,
268279
83BAC28E2538CC56004D59BC /* FramedImage.swift in Sources */,
280+
8300055D2541B34A0069A8D1 /* Secrets.swift in Sources */,
269281
834ADB3925397DE1002D9F1E /* MovieInfoOverView.swift in Sources */,
270282
833CB265253A147500E1D15C /* UIApplication+version+build.swift in Sources */,
271283
8316E0E624A64AD300467F14 /* SceneDelegate.swift in Sources */,
@@ -428,7 +440,7 @@
428440
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
429441
CODE_SIGN_IDENTITY = "Apple Development";
430442
CODE_SIGN_STYLE = Automatic;
431-
CURRENT_PROJECT_VERSION = 25;
443+
CURRENT_PROJECT_VERSION = 27;
432444
DEVELOPMENT_ASSET_PATHS = "\"TheatricalMovieTrailers/Preview Content\"";
433445
DEVELOPMENT_TEAM = U96PJYMZWW;
434446
ENABLE_PREVIEWS = YES;
@@ -453,7 +465,7 @@
453465
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
454466
CODE_SIGN_IDENTITY = "Apple Development";
455467
CODE_SIGN_STYLE = Automatic;
456-
CURRENT_PROJECT_VERSION = 25;
468+
CURRENT_PROJECT_VERSION = 27;
457469
DEVELOPMENT_ASSET_PATHS = "\"TheatricalMovieTrailers/Preview Content\"";
458470
DEVELOPMENT_TEAM = U96PJYMZWW;
459471
ENABLE_PREVIEWS = YES;

TheatricalMovieTrailers/AppDelegate.swift

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,47 +10,11 @@ import SwiftUI
1010

1111
@UIApplicationMain
1212
class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
13-
@Published var selectedTrailerModel: MovieInfo? {
14-
didSet {
15-
if let model = selectedTrailerModel {
16-
self.posterImage = idsAndImages[model.id] ?? nil
17-
}
18-
if isPlaying {
19-
isPlaying = false
20-
if selectedTrailerModel != nil {
21-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
22-
self.isPlaying = true
23-
}
24-
}
25-
}
26-
}
27-
}
2813
@Published var isExternalScreenConnected = false
2914
@Published var isPlaying = false
30-
@Published var posterImage: UIImage?
31-
32-
@Published var idsAndImages = [Int: UIImage?]()
3315

3416
var externalWindow: UIWindow?
3517
var externalVC: UIViewController?
36-
37-
func fetchImagesFor(model movies: [MovieInfo]) {
38-
DispatchQueue.global(qos: .userInitiated).async {
39-
movies.forEach { movieInfo in
40-
if let url = movieInfo.posterURL, let data = try? Data(contentsOf: url) {
41-
let image = UIImage(data: data)
42-
DispatchQueue.main.async {
43-
self.idsAndImages.updateValue(image, forKey: movieInfo.id)
44-
}
45-
} else {
46-
DispatchQueue.main.async {
47-
self.idsAndImages.updateValue(nil, forKey: movieInfo.id)
48-
}
49-
}
50-
}
51-
}
52-
}
53-
5418

5519
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
5620
// Override point for customization after application launch.
@@ -95,16 +59,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate, ObservableObject {
9559
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
9660
}
9761
}
98-
99-
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
100-
// Called when the user discards a scene session.
101-
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
102-
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
103-
if sceneSessions.first?.role == UISceneSession.Role.windowApplication {
104-
idsAndImages.removeAll()
105-
}
106-
}
107-
108-
10962
}
11063

TheatricalMovieTrailers/ContentView.swift

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,28 @@
88
import SwiftUI
99

1010
struct ContentView: View {
11-
@ObservedObject var settings = Settings.instance()
12-
@ObservedObject var appDelegate = UIApplication.shared.delegate as! AppDelegate
13-
@EnvironmentObject var sceneDelegate: SceneDelegate
11+
@ObservedObject var settings = Settings.instance
12+
@EnvironmentObject var dataStore: MovieInfoDataStore
1413
@State var sortingMode = SortingMode.ReleaseAscending
1514

1615
var body: some View {
1716
ZStack {
18-
if let model = sceneDelegate.model, appDelegate.idsAndImages.count == model.count {
17+
if let model = dataStore.model, dataStore.idsAndImages.count == model.count {
1918
MovieInfoOverView(model: model)
2019
}
2120
}
2221
.overlay(
2322
ZStack {
24-
if sceneDelegate.model == nil || appDelegate.idsAndImages.count != sceneDelegate.model!.count {
25-
ProgressView()
23+
if dataStore.model.count == 0 || dataStore.idsAndImages.count != dataStore.model.count {
24+
ProgressView("Loading Trailers…", value: Float(dataStore.idsAndImages.count), total: Float(max(dataStore.model.count, 1)))
25+
.frame(width: 200, height: 44)
2626
}
2727
}
2828
.edgesIgnoringSafeArea(.all)
2929
)
30+
.alert(item: $dataStore.error, content: { error -> Alert in
31+
error.makeAlert()
32+
})
3033
.transition(.opacity)
3134
.modifier(CustomDarkAppearance())
3235
.statusBar(hidden: true)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// AppError.swift
3+
// TheatricalMovieTrailers
4+
//
5+
// Created by Christoph Parstorfer on 22.10.20.
6+
//
7+
8+
import SwiftUI
9+
10+
enum AppError: Error, Identifiable {
11+
var id: Int {
12+
switch self {
13+
case .notConnectedToInternet:
14+
return 1
15+
default:
16+
return 0
17+
}
18+
}
19+
20+
case notConnectedToInternet
21+
case otherError(error: Error?)
22+
23+
func makeAlert() -> Alert {
24+
let title: Text
25+
let message: Text?
26+
switch self {
27+
case .notConnectedToInternet:
28+
title = Text("An internet connection is required to proceed.")
29+
message = nil
30+
case .otherError(let error):
31+
title = Text("An unknown error occurred.")
32+
message = error != nil ? Text(error!.localizedDescription) : nil
33+
}
34+
35+
return Alert(title: title, message: message, dismissButton: .default(Text("Ok")))
36+
}
37+
}

TheatricalMovieTrailers/Model/MovieInfo.swift

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -75,35 +75,6 @@ struct MovieInfo: Identifiable, Hashable {
7575
#endif
7676
}
7777

78-
// MARK: - Load Movie Info from XML & URL
79-
80-
extension MovieInfo {
81-
static func loadTrailers(loadHighDefinition: Bool = true, parserDelegate: MovieInfoXMLParserDelegate) {
82-
var urlString: String!
83-
if loadHighDefinition {
84-
urlString = "https://trailers.apple.com/trailers/home/xml/current_720p.xml"
85-
} else {
86-
urlString = "https://trailers.apple.com/trailers/home/xml/current.xml"
87-
}
88-
let url = URL(string: urlString)!
89-
loadFromURL(url, parserDelegate: parserDelegate)
90-
}
91-
92-
private static func loadFromURL(_ url: URL, parserDelegate: MovieInfoXMLParserDelegate) {
93-
DispatchQueue.global(qos: .userInitiated).async {
94-
if let xmlParser = XMLParser(contentsOf: url) {
95-
xmlParser.delegate = parserDelegate
96-
xmlParser.parse()
97-
// when finished, completion is called by the parser
98-
} else {
99-
DispatchQueue.main.async {
100-
parserDelegate.completion(nil)
101-
}
102-
}
103-
}
104-
}
105-
}
106-
10778
fileprivate class MutableMovieInfo {
10879
enum ExpectedValue {
10980
case title, posterURL, trailerURL, trailerLength, synopsis, studio, director, actors, genres, releaseDate, copyright, none

0 commit comments

Comments
 (0)