Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Movie list item #184

Merged
merged 1 commit into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 204 additions & 0 deletions Sources/TMDb/Domain/Models/MovieListItem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
//
// MovieListItem.swift
// TMDb
//
// Copyright © 2024 Adam Young.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an AS IS BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation

///
/// A model representing a movie.
///
public struct MovieListItem: Identifiable, Codable, Equatable, Hashable, Sendable {

///
/// Movie identifier.
///
public let id: Int

///
/// Movie title.
///
public let title: String

///
/// Original movie title.
///
public let originalTitle: String

///
/// Original language of the movie.
///
public let originalLanguage: String

///
/// Movie overview.
///
public let overview: String

///
/// Movie genre identifiers.
///
public let genreIDs: [Genre.ID]

///
/// Movie release date.
///
public let releaseDate: Date?

///
/// Movie poster path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let posterPath: URL?

///
/// Movie poster backdrop path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let backdropPath: URL?

///
/// Current popularity.
///
public let popularity: Double?

///
/// Average vote score.
///
public let voteAverage: Double?

///
/// Number of votes.
///
public let voteCount: Int?

///
/// Has video.
///
public let hasVideo: Bool?

///
/// Is the movie only suitable for adults.
///
public let isAdultOnly: Bool?

///
/// Creates a movie list item object.
///
/// - Parameters:
/// - id: Movie identifier.
/// - title: Movie title.
/// - tagline: Movie tagline.
/// - originalTitle: Original movie title.
/// - originalLanguage: Original language of the movie.
/// - overview: Movie overview.
/// - genreID: Movie genre identifiers.
/// - releaseDate: Movie release date.
/// - posterPath: Movie poster path.
/// - backdropPath: Movie poster backdrop path.
/// - popularity: Current popularity.
/// - voteAverage: Average vote score.
/// - voteCount: Number of votes.
/// - hasVideo: Has video.
/// - isAdultOnly: Is the movie only suitable for adults.
///
public init(
id: Int,
title: String,
originalTitle: String,
originalLanguage: String,
overview: String,
genreIDs: [Genre.ID],
releaseDate: Date? = nil,
posterPath: URL? = nil,
backdropPath: URL? = nil,
popularity: Double? = nil,
voteAverage: Double? = nil,
voteCount: Int? = nil,
hasVideo: Bool? = nil,
isAdultOnly: Bool? = nil
) {
self.id = id
self.title = title
self.originalTitle = originalTitle
self.originalLanguage = originalLanguage
self.overview = overview
self.genreIDs = genreIDs
self.releaseDate = releaseDate
self.posterPath = posterPath
self.backdropPath = backdropPath
self.popularity = popularity
self.voteAverage = voteAverage
self.voteCount = voteCount
self.hasVideo = hasVideo
self.isAdultOnly = isAdultOnly
}

}

extension MovieListItem {

private enum CodingKeys: String, CodingKey {
case id
case title
case originalTitle
case originalLanguage
case overview
case genreIDs = "genreIds"
case releaseDate
case posterPath
case backdropPath
case popularity
case voteAverage
case voteCount
case hasVideo = "video"
case isAdultOnly = "adult"
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let container2 = try decoder.container(keyedBy: CodingKeys.self)

self.id = try container.decode(Int.self, forKey: .id)
self.title = try container.decode(String.self, forKey: .title)
self.originalTitle = try container.decode(String.self, forKey: .originalTitle)
self.originalLanguage = try container.decode(String.self, forKey: .originalLanguage)
self.overview = try container.decode(String.self, forKey: .overview)
self.genreIDs = try container.decode([Genre.ID].self, forKey: .genreIDs)

// Need to deal with empty strings - date decoding will fail with an empty string
let releaseDateString = try container.decodeIfPresent(String.self, forKey: .releaseDate)
self.releaseDate = try {
guard let releaseDateString, !releaseDateString.isEmpty else {
return nil
}

return try container2.decodeIfPresent(Date.self, forKey: .releaseDate)
}()

self.posterPath = try container.decodeIfPresent(URL.self, forKey: .posterPath)
self.backdropPath = try container.decodeIfPresent(URL.self, forKey: .backdropPath)
self.popularity = try container.decodeIfPresent(Double.self, forKey: .popularity)
self.voteAverage = try container.decodeIfPresent(Double.self, forKey: .voteAverage)
self.voteCount = try container.decodeIfPresent(Int.self, forKey: .voteCount)
self.hasVideo = try container.decodeIfPresent(Bool.self, forKey: .hasVideo)
self.isAdultOnly = try container.decodeIfPresent(Bool.self, forKey: .isAdultOnly)
}

}
2 changes: 1 addition & 1 deletion Sources/TMDb/Domain/Models/MoviePageableList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ import Foundation
///
/// A model representing a pageable list of movies.
///
public typealias MoviePageableList = PageableListResult<Movie>
public typealias MoviePageableList = PageableListResult<MovieListItem>
56 changes: 56 additions & 0 deletions Tests/TMDbTests/Domain/Models/MovieListItemTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// MovieListItemTests.swift
// TMDb
//
// Copyright © 2024 Adam Young.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an AS IS BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

@testable import TMDb
import XCTest

final class MovieListItemTests: XCTestCase {

func testDecodeReturnsMovieListItem() throws {
let result = try JSONDecoder.theMovieDatabase.decode(MovieListItem.self, fromResource: "movie-list-item")

XCTAssertEqual(result, movie)
}

}

extension MovieListItemTests {

// swiftlint:disable line_length
private var movie: MovieListItem {
.init(
id: 437_342,
title: "The First Omen",
originalTitle: "The First Omen",
originalLanguage: "en",
overview: "When a young American woman is sent to Rome to begin a life of service to the church, she encounters a darkness that causes her to question her own faith and uncovers a terrifying conspiracy that hopes to bring about the birth of evil incarnate.",
genreIDs: [27],
releaseDate: DateFormatter.theMovieDatabase.date(from: "2024-04-05"),
posterPath: URL(string: "/uGyiewQnDHPuiHN9V4k2t9QBPnh.jpg"),
backdropPath: URL(string: "/tkHQ7tnYYUEnqlrKuhufIsSVToU.jpg"),
popularity: 1080.713,
voteAverage: 6.768,
voteCount: 455,
hasVideo: false,
isAdultOnly: false
)
}
// swiftlint:enable line_length

}
27 changes: 24 additions & 3 deletions Tests/TMDbTests/Domain/Models/MoviePageableListTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,30 @@ final class MoviePageableListTests: XCTestCase {
private let list = MoviePageableList(
page: 1,
results: [
Movie(id: 1, title: "Movie 1"),
Movie(id: 2, title: "Movie 2"),
Movie(id: 3, title: "Movie 3")
MovieListItem(
id: 1,
title: "Movie 1",
originalTitle: "Movie 1 - a",
originalLanguage: "en",
overview: "Overview 1",
genreIDs: [1, 2, 3]
),
MovieListItem(
id: 2,
title: "Movie 2",
originalTitle: "Movie 2 - a",
originalLanguage: "en",
overview: "Overview 2",
genreIDs: [4, 5, 6]
),
MovieListItem(
id: 3,
title: "Movie 3",
originalTitle: "Movie 3 - a",
originalLanguage: "en",
overview: "Overview 3",
genreIDs: [7, 8, 9]
)
],
totalResults: 3,
totalPages: 1
Expand Down
Loading
Loading