Skip to content

Commit fa119de

Browse files
Added screenshots to README
Fixed some unit tests
1 parent 2a57bd4 commit fa119de

File tree

12 files changed

+67
-52
lines changed

12 files changed

+67
-52
lines changed

Movie DB/CSV/CSVHelper.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import Foundation
1313
struct CSVHelper {
1414
private init() {}
1515

16+
// TODO: Make async and use continuation to return the result (or throw an error)
1617
static func importMediaObjects(
1718
csvString: String,
1819
importContext: NSManagedObjectContext,

Movie DB/CoreData/Model/Media/Media+CoreDataClass.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,18 @@ public class Media: NSManagedObject {
2121

2222
// Loads the poster thumbnail in the background and assigns it to this media's thumbnail property
2323
func loadThumbnail(force: Bool = false) async {
24-
guard force || managedObjectContext?.performAndWait({ self.thumbnail }) == nil else {
25-
// Thumbnail already present, don't load/download again, unless force parameter is given
24+
guard
25+
let managedObjectContext,
26+
force || managedObjectContext.performAndWait({ self.thumbnail }) == nil
27+
else {
28+
// Thumbnail already present or no context, don't load/download again, unless force parameter is given
2629
return
2730
}
2831
do {
29-
let mediaID = managedObjectContext?.performAndWait { self.id }
30-
let imagePath = managedObjectContext?.performAndWait { self.imagePath }
32+
let mediaID = managedObjectContext.performAndWait { self.id }
33+
let imagePath = managedObjectContext.performAndWait { self.imagePath }
3134
let thumbnail = try await PosterService.shared.thumbnail(for: mediaID, imagePath: imagePath, force: force)
32-
assert(self.managedObjectContext != nil)
33-
self.managedObjectContext?.performAndWait {
35+
managedObjectContext.performAndWait {
3436
self.objectWillChange.send()
3537
self.thumbnail = thumbnail
3638
}
@@ -115,8 +117,8 @@ public class Media: NSManagedObject {
115117
print("[\(title)] Awaking from insert")
116118
tags = []
117119
// Use `setPrimitiveValue` to avoid sending notifications
118-
setPrimitiveValue(Date(), forKey: "creationDate")
119-
setPrimitiveValue(Date(), forKey: "modificationDate")
120+
self.creationDate = .now
121+
self.modificationDate = .now
120122
}
121123

122124
override public func willSave() {

Movie DB/Utility/PlaceholderData.swift

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,24 +33,27 @@ enum PlaceholderData {
3333
return s
3434
}()
3535

36-
static let allTags: [Tag] = [
37-
Tag(name: "Future", context: context),
38-
Tag(name: "Conspiracy", context: context),
39-
Tag(name: "Dark", context: context),
40-
Tag(name: "Violent", context: context),
41-
Tag(name: "Gangsters", context: context),
42-
Tag(name: "Terrorist", context: context),
43-
Tag(name: "Past", context: context),
44-
Tag(name: "Fantasy", context: context),
45-
]
36+
static func mapTags(_ tagNames: [String], in context: NSManagedObjectContext) -> Set<Tag> {
37+
var tags: Set<Tag> = []
38+
for name in tagNames {
39+
let fetchRequest = Tag.fetchRequest()
40+
fetchRequest.predicate = NSPredicate(format: "name = %@", name)
41+
if let tag = try? context.fetch(fetchRequest).first {
42+
// Use the existing tag
43+
tags.insert(tag)
44+
} else {
45+
// Create a new one
46+
tags.insert(Tag(name: name, context: context))
47+
}
48+
}
49+
return tags
50+
}
4651

47-
// swiftlint:disable:next function_body_length
48-
static func createMovie() -> Movie {
52+
static func createMovie(in context: NSManagedObjectContext = context) -> Movie {
4953
let tmdbData: TMDBData = Self.load("Matrix.json", mediaType: .movie, into: context)
5054
let m = Movie(context: context, tmdbData: tmdbData)
5155
m.personalRating = .twoAndAHalfStars
52-
m.tags = Set(["Future", "Conspiracy", "Dark"]
53-
.map { name in allTags.first(where: { $0.name == name })! })
56+
m.tags = mapTags(["Future", "Conspiracy", "Dark"], in: context)
5457
m.notes = ""
5558
m.watched = .watched
5659
m.watchAgain = false
@@ -109,12 +112,11 @@ enum PlaceholderData {
109112
return m
110113
}
111114

112-
static func createShow() -> Show {
115+
static func createShow(in context: NSManagedObjectContext = context) -> Show {
113116
let tmdbData: TMDBData = Self.load("Blacklist.json", mediaType: .show, into: context)
114117
let s = Show(context: context, tmdbData: tmdbData)
115118
s.personalRating = .fiveStars
116-
s.tags = Set(["Gangsters", "Conspiracy", "Terrorist"]
117-
.map { name in allTags.first(where: { $0.name == name })! })
119+
s.tags = mapTags(["Gangsters", "Conspiracy", "Terrorist"], in: context)
118120
s.notes = "A masterpiece!"
119121
s.watched = .season(7)
120122
s.watchAgain = true

Movie DBTests/CSVCoderTests.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,15 @@ class CSVCoderTests: XCTestCase {
100100
try await Task.sleep(for: .seconds(3))
101101

102102
// MARK: Decode
103-
let expectation = XCTestExpectation(description: "Decode CSV")
103+
let expectation = expectation(description: "Decode CSV")
104104
let disposableContext = PersistenceController.createDisposableContext()
105-
CSVHelper.importMediaObjects(csvString: csv, importContext: disposableContext) { mediaObjects, _ in
105+
CSVHelper.importMediaObjects(csvString: csv, importContext: disposableContext) { _ in
106+
// onProgress
107+
} onFail: { importLog in
108+
XCTFail("CSVHelper failed importing the media objects.")
109+
print(importLog.joined(separator: "\n"))
110+
expectation.fulfill()
111+
} onFinish: { mediaObjects, _ in
106112
do {
107113
XCTAssertEqual(mediaObjects.count, samples.count)
108114

@@ -138,12 +144,11 @@ class CSVCoderTests: XCTestCase {
138144
} catch {
139145
XCTFail(error.localizedDescription)
140146
}
141-
// Fulfill the expectation.
142147
expectation.fulfill()
143148
}
144149

145150
// Wait for decoding tests to finish
146-
wait(for: [expectation], timeout: 10.0)
151+
await waitForExpectations(timeout: 20)
147152
}
148153

149154
// Compares if two dates by comparing their ISO8601 representation
@@ -203,7 +208,7 @@ class CSVCoderTests: XCTestCase {
203208
XCTAssertEqual(data[.isAdult], movie.isAdult.description)
204209
} else if let show = media as? Show {
205210
// Show exclusive
206-
XCTAssertEqual(data[.lastSeasonWatched], show.watched?.season?.description ?? "")
211+
XCTAssertEqual(data[.lastSeasonWatched], show.watched?.season.description ?? "")
207212
XCTAssertEqual(data[.lastEpisodeWatched], show.watched?.episode?.description ?? "")
208213
if let firstAirDate = show.firstAirDate {
209214
XCTAssertEqual(data[.firstAirDate], CSVManager.dateFormatter.string(from: firstAirDate))

Movie DBTests/PredicateTests.swift

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,40 +30,36 @@ class PredicateTests: XCTestCase {
3030
}
3131

3232
func testNewSeasonsAvailablePredicate() throws {
33-
let predicateCompletelyWatched = NSCompoundPredicate(type: .and, subpredicates: [
33+
let predicateNotCompletelyWatched = NSCompoundPredicate(type: .and, subpredicates: [
3434
NSPredicate(format: "type = %@", MediaType.show.rawValue),
3535
NSPredicate(format: "lastSeasonWatched > 0 AND lastSeasonWatched < numberOfSeasons"),
3636
])
3737

38-
PlaceholderData.context.reset()
38+
let media1 = PlaceholderData.createShow(in: testingUtils.context)
39+
media1.title = "Media 1"
40+
media1.numberOfSeasons = 11
41+
media1.watched = .season(11)
3942

40-
let matchingMedia1 = PlaceholderData.createShow()
41-
matchingMedia1.title = "Media 1"
42-
matchingMedia1.numberOfSeasons = 11
43-
matchingMedia1.watched = .season(11)
43+
let media2 = PlaceholderData.createShow(in: testingUtils.context)
44+
media2.title = "Media 2"
45+
media2.numberOfSeasons = 1
46+
media2.watched = .season(11)
4447

45-
let matchingMedia2 = PlaceholderData.createShow()
46-
matchingMedia2.title = "Media 2"
47-
matchingMedia2.numberOfSeasons = 1
48-
matchingMedia2.watched = .season(11)
49-
50-
let nonMatchingMedia = PlaceholderData.createShow()
51-
nonMatchingMedia.title = "Media 3"
52-
nonMatchingMedia.numberOfSeasons = 11
53-
nonMatchingMedia.watched = .season(1)
48+
let media3 = PlaceholderData.createShow(in: testingUtils.context)
49+
media3.title = "Media 3"
50+
media3.numberOfSeasons = 11
51+
media3.watched = .season(1)
5452

5553
let fetchRequest = Media.fetchRequest()
56-
fetchRequest.predicate = predicateCompletelyWatched
54+
fetchRequest.predicate = predicateNotCompletelyWatched
5755
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)]
58-
let results = try PlaceholderData.context.fetch(fetchRequest)
56+
let results = try testingUtils.context.fetch(fetchRequest)
5957

60-
XCTAssertEqual(results.map(\.title), [matchingMedia1.title, matchingMedia2.title])
58+
XCTAssertEqual(results.map(\.title), [media3.title])
6159
}
6260

6361
func testAnyPredicate() throws {
64-
PlaceholderData.context.reset()
65-
66-
let show = PlaceholderData.createShow()
62+
let show = PlaceholderData.createShow(in: testingUtils.context)
6763
show.watched = .season(1)
6864
show.numberOfSeasons = 2
6965

@@ -75,7 +71,7 @@ class PredicateTests: XCTestCase {
7571

7672
let fetchRequest: NSFetchRequest<Show> = Show.fetchRequest()
7773
fetchRequest.predicate = predicate
78-
let results = try PlaceholderData.context.fetch(fetchRequest)
74+
let results = try testingUtils.context.fetch(fetchRequest)
7975
XCTAssertEqual(results.count, 1)
8076
print(results)
8177
}

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ An app to keep track of all the movies and shows you watched.
55

66
**Download now via [TestFlight](https://testflight.apple.com/join/yI9GMaOD)!**
77

8+
<p align="center">
9+
<img src="./readme_images/01_Library.png" width="16%" />
10+
<img src="./readme_images/02_AddMedia.png" width="16%" />
11+
<img src="./readme_images/03_Lists.png" width="16%" />
12+
<img src="./readme_images/04_Watchlist.png" width="16%" />
13+
<img src="./readme_images/05_ListConfiguration.png" width="16%" />
14+
<img src="./readme_images/06_Settings.png" width="16%" />
15+
</p>
16+
817

918
## Features
1019
* Add movies and tv shows from TheMovieDB.org to your library

readme_images/01_Library.png

567 KB
Loading

readme_images/02_AddMedia.png

667 KB
Loading

readme_images/03_Lists.png

137 KB
Loading

readme_images/04_Watchlist.png

326 KB
Loading

0 commit comments

Comments
 (0)