diff --git a/MovieVerse-Mobile/app/ios/AboutViewController.swift b/MovieVerse-Mobile/app/ios/AboutViewController.swift
new file mode 100644
index 00000000..8c8922b7
--- /dev/null
+++ b/MovieVerse-Mobile/app/ios/AboutViewController.swift
@@ -0,0 +1,121 @@
+import UIKit
+
+// MARK: - Data Model
+struct AboutSection {
+ let title: String
+ let description: String
+}
+
+class AboutViewController: UIViewController {
+
+ // Data
+ private let sections: [AboutSection] = [
+ AboutSection(title: "Welcome to The MovieVerse",
+ description: "Your ultimate destination for exploring the magic of movies. Here, you can discover, engage, and immerse yourself in the world of film."),
+ AboutSection(title: "Core Features",
+ description: "Explore movies by genre, director, language, and era. Enjoy interactive movie details, high-quality trailers, and a community-driven recommendation system."),
+ AboutSection(title: "Our Vision",
+ description: "We aim to create a haven for cinephiles, where discovery of movies is an adventure. It's a vibrant community for sharing cinematic experiences and insights."),
+ AboutSection(title: "Join The Journey",
+ description: "We're constantly innovating to bring you new and exciting features. Your engagement and feedback are invaluable to us.")
+ ]
+
+ // UI Components
+ private lazy var tableView: UITableView = {
+ let table = UITableView()
+ table.delegate = self
+ table.dataSource = self
+ table.register(AboutSectionCell.self, forCellReuseIdentifier: AboutSectionCell.identifier)
+ return table
+ }()
+
+ // MARK: - Lifecycle
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupUI()
+ }
+
+ // MARK: - Setup
+ private func setupUI() {
+ view.addSubview(tableView)
+ tableView.frame = view.bounds
+ title = "About The MovieVerse"
+ }
+}
+
+// MARK: - UITableView DataSource & Delegate
+extension AboutViewController: UITableViewDataSource, UITableViewDelegate {
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return sections.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: AboutSectionCell.identifier, for: indexPath) as? AboutSectionCell else {
+ return UITableViewCell()
+ }
+ let section = sections[indexPath.row]
+ cell.configure(with: section)
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+ return UITableView.automaticDimension
+ }
+}
+
+// MARK: - Custom TableViewCell
+class AboutSectionCell: UITableViewCell {
+
+ static let identifier = "AboutSectionCell"
+
+ private let titleLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.boldSystemFont(ofSize: 18)
+ label.numberOfLines = 0
+ return label
+ }()
+
+ private let descriptionLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.systemFont(ofSize: 16)
+ label.numberOfLines = 0
+ label.textColor = .darkGray
+ return label
+ }()
+
+ // Initialization
+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+ contentView.addSubview(titleLabel)
+ contentView.addSubview(descriptionLabel)
+ applyConstraints()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // Configure Cell
+ func configure(with section: AboutSection) {
+ titleLabel.text = section.title
+ descriptionLabel.text = section.description
+ }
+
+ // Constraints
+ private func applyConstraints() {
+ titleLabel.translatesAutoresizingMaskIntoConstraints = false
+ descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
+
+ NSLayoutConstraint.activate([
+ titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
+ titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
+ titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
+
+ descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 5),
+ descriptionLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
+ descriptionLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
+ descriptionLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -10)
+ ])
+ }
+}
diff --git a/MovieVerse-Mobile/app/ios/ActorDetailsViewController.swift b/MovieVerse-Mobile/app/ios/ActorDetailsViewController.swift
new file mode 100644
index 00000000..5784b266
--- /dev/null
+++ b/MovieVerse-Mobile/app/ios/ActorDetailsViewController.swift
@@ -0,0 +1,96 @@
+import UIKit
+
+// MARK: - Actor Data Model
+struct Actor {
+ let id: Int
+ let name: String
+ let bio: String
+ let birthDate: String
+ let filmography: [String]
+}
+
+class ActorDetailsViewController: UIViewController {
+
+ var actor: Actor? // Actor data passed from the previous screen
+
+ // UI Components
+ private let nameLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.boldSystemFont(ofSize: 24)
+ label.textAlignment = .center
+ return label
+ }()
+
+ private let bioLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.systemFont(ofSize: 16)
+ label.numberOfLines = 0
+ label.textAlignment = .left
+ return label
+ }()
+
+ private let tableView: UITableView = {
+ let table = UITableView()
+ table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
+ return table
+ }()
+
+ // MARK: - Lifecycle
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupUI()
+ configureTableView()
+ loadActorDetails()
+ }
+
+ // MARK: - Setup
+ private func setupUI() {
+ view.backgroundColor = .white
+ view.addSubview(nameLabel)
+ view.addSubview(bioLabel)
+ view.addSubview(tableView)
+ layoutUI()
+ }
+
+ private func configureTableView() {
+ tableView.dataSource = self
+ tableView.delegate = self
+ }
+
+ private func layoutUI() {
+ nameLabel.translatesAutoresizingMaskIntoConstraints = false
+ bioLabel.translatesAutoresizingMaskIntoConstraints = false
+ tableView.translatesAutoresizingMaskIntoConstraints = false
+ dobLabel.translatesAutoresizingMaskIntoConstraints = false
+ ageLabel.translatesAutoresizingMaskIntoConstraints = false
+ filmographyLabel.translatesAutoresizingMaskIntoConstraints = false
+ heightLabel.translatesAutoresizingMaskIntoConstraints = false
+ }
+
+ private func loadActorDetails() {
+ guard let actor = actor else { return }
+ nameLabel.text = actor.name
+ bioLabel.text = "Biography: \(actor.bio)"
+
+ tableView.reloadData()
+ }
+}
+
+// MARK: - UITableViewDataSource, UITableViewDelegate
+extension ActorDetailsViewController: UITableViewDataSource, UITableViewDelegate {
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return actor?.filmography.count ?? 0
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
+ cell.textLabel?.text = actor?.filmography[indexPath.row]
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ tableView.deselectRow(at: indexPath, animated: true)
+ tableView.reloadData()
+ }
+}
diff --git a/MovieVerse-Mobile/app/ios/DirectorDetailsViewController.swift b/MovieVerse-Mobile/app/ios/DirectorDetailsViewController.swift
new file mode 100644
index 00000000..ba3d1ce5
--- /dev/null
+++ b/MovieVerse-Mobile/app/ios/DirectorDetailsViewController.swift
@@ -0,0 +1,106 @@
+import UIKit
+
+// MARK: - Director Data Model
+struct Director {
+ let id: Int
+ let name: String
+ let bio: String
+ let birthDate: String
+ let filmography: [String]
+}
+
+class DirectorDetailsViewController: UIViewController {
+
+ var directorId: Int? // Director ID passed from the previous screen
+
+ // UI Components
+ private let nameLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.boldSystemFont(ofSize: 24)
+ label.textAlignment = .center
+ return label
+ }()
+
+ private let bioTextView: UITextView = {
+ let textView = UITextView()
+ textView.font = UIFont.systemFont(ofSize: 16)
+ textView.isEditable = false
+ return textView
+ }()
+
+ private let tableView: UITableView = {
+ let table = UITableView()
+ table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
+ return table
+ }()
+
+ // MARK: - Lifecycle
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupUI()
+ configureTableView()
+ loadDirectorDetails()
+ }
+
+ // MARK: - Setup
+ private func setupUI() {
+ view.backgroundColor = .white
+ view.addSubview(nameLabel)
+ view.addSubview(bioTextView)
+ view.addSubview(tableView)
+ layoutUI()
+ }
+
+ private func configureTableView() {
+ tableView.dataSource = self
+ tableView.delegate = self
+ }
+
+ private func layoutUI() {
+ // Constraints setup for nameLabel, bioTextView, and tableView
+ }
+
+ private func loadDirectorDetails() {
+ guard let directorId = directorId else { return }
+ fetchDirectorDetails(directorId: directorId)
+ }
+
+ private func fetchDirectorDetails(directorId: Int) {}
+ let sampleDirector = Director(id: directorId, name: "Christopher Nolan", bio: "An acclaimed British-American film director...", birthDate: "1970-07-30", filmography: ["Inception", "The Dark Knight", "Interstellar"])
+
+ nameLabel.text = sampleDirector.name
+ bioTextView.text = "Bio: \(sampleDirector.bio)\n\nBorn: \(sampleDirector.birthDate)"
+
+ apiClient.fetchDirectorFilmography(directorId: directorId) { result in
+ switch result {
+ case .success(let movies):
+ director.filmography = movies.map { $0.title }
+ case .failure(let error):
+ print(error.localizedDescription)
+ }
+ }
+
+ resultsLabel.text = "Filmography"
+
+ tableView.reloadData()
+ }
+}
+
+// MARK: - UITableViewDataSource, UITableViewDelegate
+extension DirectorDetailsViewController: UITableViewDataSource, UITableViewDelegate {
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return 3 // Sample data
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
+ cell.textLabel?.text = ["Inception", "The Dark Knight", "Interstellar"][indexPath.row]
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ tableView.deselectRow(at: indexPath, animated: true)
+ movieDetails(movie: ["Inception", "The Dark Knight", "Interstellar"][indexPath.row])
+ }
+}
diff --git a/MovieVerse-Mobile/app/ios/MovieDetailViewController.swift b/MovieVerse-Mobile/app/ios/MovieDetailViewController.swift
index 7a238d28..6d6c2354 100644
--- a/MovieVerse-Mobile/app/ios/MovieDetailViewController.swift
+++ b/MovieVerse-Mobile/app/ios/MovieDetailViewController.swift
@@ -442,4 +442,4 @@ struct MoviesViewController: UIViewController, UITableViewDelegate, UITableViewD
movieDetailViewController.movie = movie
}
}
-}
\ No newline at end of file
+}
diff --git a/MovieVerse-Mobile/app/ios/MovieDetailsView.swift b/MovieVerse-Mobile/app/ios/MovieDetailsView.swift
index 7eb4fcc5..e49be084 100644
--- a/MovieVerse-Mobile/app/ios/MovieDetailsView.swift
+++ b/MovieVerse-Mobile/app/ios/MovieDetailsView.swift
@@ -72,7 +72,7 @@ struct MoviePosterImage: View {
}.resume()
}
- private func fetchImageData() {
+ private func fetchImageData2() {
URLSession.shared.dataTaskPublisher(for: url)
.map { $0.data }
.replaceError(with: nil)
diff --git a/MovieVerse-Mobile/app/ios/MovieTimelineViewController.swift b/MovieVerse-Mobile/app/ios/MovieTimelineViewController.swift
new file mode 100644
index 00000000..b9f89e33
--- /dev/null
+++ b/MovieVerse-Mobile/app/ios/MovieTimelineViewController.swift
@@ -0,0 +1,203 @@
+import UIKit
+
+// MARK: - Data Model
+struct MovieTimelineSection {
+ let period: String
+ let movies: [Movie]
+}
+
+struct Movie {
+ let title: String
+ let releaseYear: String
+ let description: String
+ let posterURL: String
+}
+
+class MovieTimelineViewController: UIViewController {
+
+ // Sample Data
+ private let timelineSections: [MovieTimelineSection] = [
+ MovieTimelineSection(period: "1920s", movies: [Movie(title: "Movie 1", releaseYear: "1920", description: "Description 1", posterURL: "URL1")]),
+ MovieTimelineSection(period: "1930s", movies: [Movie(title: "Movie 2", releaseYear: "1930", description: "Description 2", posterURL: "URL2")]),
+ MovieTimelineSection(period: "1940s", movies: [Movie(title: "Movie 3", releaseYear: "1940", description: "Description 3", posterURL: "URL3")]),
+ MovieTimelineSection(period: "1950s", movies: [Movie(title: "Movie 4", releaseYear: "1950", description: "Description 4", posterURL: "URL4")]),
+ MovieTimelineSection(period: "1960s", movies: [Movie(title: "Movie 5", releaseYear: "1960", description: "Description 5", posterURL: "URL5")]),
+ MovieTimelineSection(period: "1970s", movies: [Movie(title: "Movie 6", releaseYear: "1970", description: "Description 6", posterURL: "URL6")]),
+ MovieTimelineSection(period: "1980s", movies: [Movie(title: "Movie 7", releaseYear: "1980", description: "Description 7", posterURL: "URL7")]),
+ MovieTimelineSection(period: "1990s", movies: [Movie(title: "Movie 8", releaseYear: "1990", description: "Description 8", posterURL: "URL8")]),
+ MovieTimelineSection(period: "2000s", movies: [Movie(title: "Movie 9", releaseYear: "2000", description: "Description 9", posterURL: "URL9")]),
+ MovieTimelineSection(period: "2010s", movies: [Movie(title: "Movie 10", releaseYear: "2010", description: "Description 10", posterURL: "URL10")]),
+ MovieTimelineSection(period: "2020s", movies: [Movie(title: "Movie 11", releaseYear: "2020", description: "Description 11", posterURL: "URL11")])
+ ]
+
+ // UI Components
+ private lazy var tableView: UITableView = {
+ let table = UITableView()
+ table.delegate = self
+ table.dataSource = self
+ table.register(MovieTimelineCell.self, forCellReuseIdentifier: MovieTimelineCell.identifier)
+ return table
+ }()
+
+ // MARK: - Lifecycle
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupUI()
+ }
+
+ // MARK: - Setup
+ private func setupUI() {
+ view.addSubview(tableView)
+ tableView.frame = view.bounds
+ title = "Movie Timeline"
+ }
+
+ // MARK: - Reuse
+ override func prepareForReuse() {
+ super.prepareForReuse()
+ tableView.reloadData()
+ }
+}
+
+// MARK: - UITableView DataSource & Delegate
+extension MovieTimelineViewController: UITableViewDataSource, UITableViewDelegate {
+
+ func numberOfSections(in tableView: UITableView) -> Int {
+ return timelineSections.count
+ }
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return timelineSections[section].movies.count
+ }
+
+ func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
+ return timelineSections[section].period
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: MovieTimelineCell.identifier, for: indexPath) as? MovieTimelineCell else {
+ return UITableViewCell()
+ }
+ let movie = timelineSections[indexPath.section].movies[indexPath.row]
+ cell.configure(with: movie)
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
+ return 120
+ }
+
+ func sectionIndexTitles(for tableView: UITableView) -> [String]? {
+ return timelineSections.map { $0.period }
+ }
+
+ func tableView(_ tableView: UITableView, sectionForSectionIndexTitle title: String, at index: Int) -> Int {
+ return timelineSections.firstIndex { $0.period == title } ?? 0
+ }
+}
+
+// MARK: - Custom TableViewCell
+class MovieTimelineCell: UITableViewCell {
+
+ static let identifier = "MovieTimelineCell"
+
+ // UI Elements for the cell
+ private let titleLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.boldSystemFont(ofSize: 18)
+ return label
+ }()
+
+ private let yearLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.systemFont(ofSize: 16)
+ label.textColor = .gray
+ return label
+ }()
+
+ private let descriptionLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.systemFont(ofSize: 16)
+ label.numberOfLines = 0
+ return label
+ }()
+
+ private let posterImageView: UIImageView = {
+ let imageView = UIImageView()
+ imageView.contentMode = .scaleAspectFit
+ imageView.clipsToBounds = true
+ return imageView
+ }()
+
+ // Initialization
+ override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
+ super.init(style: style, reuseIdentifier: reuseIdentifier)
+ setupLayout()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ // Configure Cell
+ func configure(with movie: Movie) {
+ titleLabel.text = movie.title
+ yearLabel.text = "Release Year: \(movie.releaseYear)"
+ descriptionLabel.text = movie.description
+ posterImageView.image = UIImage(named: movie.posterURL) // replace with actual image loading logic
+ }
+
+ // Layout
+ private func setupLayout() {
+ let stackView = UIStackView(arrangedSubviews: [titleLabel, yearLabel, descriptionLabel])
+ stackView.axis = .vertical
+ stackView.spacing = 4
+ stackView.translatesAutoresizingMaskIntoConstraints = false
+
+ addSubview(posterImageView)
+ addSubview(stackView)
+
+ NSLayoutConstraint.activate([
+ posterImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
+ posterImageView.topAnchor.constraint(equalTo: topAnchor, constant: 10),
+ posterImageView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10),
+ posterImageView.widthAnchor.constraint(equalToConstant: 100),
+
+ stackView.leadingAnchor.constraint(equalTo: posterImageView.trailingAnchor, constant: 10),
+ stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10),
+ stackView.topAnchor.constraint(equalTo: topAnchor, constant: 10),
+ stackView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10)
+ ])
+ }
+
+ private func applyConstraints() {
+ titleLabel.translatesAutoresizingMaskIntoConstraints = false
+ yearLabel.translatesAutoresizingMaskIntoConstraints = false
+ descriptionLabel.translatesAutoresizingMaskIntoConstraints = false
+
+ NSLayoutConstraint.activate([
+ titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 10),
+ titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
+ titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10),
+
+ yearLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 5),
+ yearLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
+ yearLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10),
+
+ descriptionLabel.topAnchor.constraint(equalTo: yearLabel.bottomAnchor, constant: 5),
+ descriptionLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10),
+ descriptionLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -10),
+ descriptionLabel.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -10)
+ ])
+ }
+
+ // MARK: - Reuse
+ override func prepareForReuse() {
+ super.prepareForReuse()
+ titleLabel.text = nil
+ yearLabel.text = nil
+ descriptionLabel.text = nil
+ posterImageView.image = nil
+ }
+
+}
diff --git a/MovieVerse-Mobile/app/ios/MovieTriviaViewController.swift b/MovieVerse-Mobile/app/ios/MovieTriviaViewController.swift
new file mode 100644
index 00000000..933f8caa
--- /dev/null
+++ b/MovieVerse-Mobile/app/ios/MovieTriviaViewController.swift
@@ -0,0 +1,186 @@
+import UIKit
+
+// MARK: - Data Model
+struct TriviaQuestion {
+ let question: String
+ let options: [String]
+ let correctAnswer: String
+}
+
+class MovieTriviaViewController: UIViewController {
+
+// Data in JS
+// const questionBank = [
+// { question: "What movie won the Academy Award for Best Picture in 2020?", options: ["Joker", "1917", "Parasite"], answer: "Parasite" },
+// { question: "Who directed the movie 'The Godfather'?", options: ["Steven Spielberg", "Francis Ford Coppola", "Martin Scorsese"], answer: "Francis Ford Coppola" },
+// { question: "What was the first feature-length animated movie ever released?", options: ["Snow White and the Seven Dwarfs", "Bambi", "Pinocchio"], answer: "Snow White and the Seven Dwarfs" },
+// { question: "What was the highest-grossing movie of all time before the release of 'Avatar'?", options: ["Titanic", "Star Wars: The Force Awakens", "Avengers: Endgame"], answer: "Titanic" },
+// { question: "Who played the lead role in the movie 'Forrest Gump'?", options: ["Tom Hanks", "Brad Pitt", "Leonardo DiCaprio"], answer: "Tom Hanks" },
+// { question: "What movie won the Academy Award for Best Picture in 2019?", options: ["Bohemian Rhapsody", "Green Book", "Roma"], answer: "Green Book" },
+// { question: "Who played the character of John McClane in the Die Hard movie series?", options: ["Arnold Schwarzenegger", "Sylvester Stallone", "Bruce Willis"], answer: "Bruce Willis" },
+// { question: "What movie is based on a novel by Stephen King and features a character named Jack Torrance?", options: ["Carrie", "The Shining", "Misery"], answer: "The Shining" },
+// { question: "Who directed the movie 'Forrest Gump'?", options: ["Steven Spielberg", "Robert Zemeckis", "Martin Scorsese"], answer: "Robert Zemeckis" },
+// { question: "What is the highest-grossing movie of all time (as of 2021)?", options: ["Avatar", "Avengers: Endgame", "Titanic"], answer: "Avatar" },
+// { question: "What movie features the line 'You can't handle the truth!'?", options: ["The Shawshank Redemption", "A Few Good Men", "Goodfellas"], answer: "A Few Good Men" },
+// { question: "Who played the character of Tony Stark/Iron Man in the Marvel Cinematic Universe?", options: ["Chris Hemsworth", "Mark Ruffalo", "Robert Downey Jr."], answer: "Robert Downey Jr." },
+// { question: "In which movie did Tom Hanks say, 'Houston, we have a problem'?", options: ["Apollo 13", "Cast Away", "The Terminal"], answer: "Apollo 13" },
+// { question: "What is the name of the hobbit played by Elijah Wood in the Lord of the Rings movies?", options: ["Frodo", "Sam", "Merry"], answer: "Frodo" },
+// { question: "What is the name of the kingdom where the 2013 animated movie 'Frozen' is set?", options: ["Arendelle", "Genovia", "DunBroch"], answer: "Arendelle" },
+// { question: "Which 1997 science fiction movie stars Will Smith and Tommy Lee Jones?", options: ["Independence Day", "Men in Black", "Wild Wild West"], answer: "Men in Black" },
+// { question: "Which movie features Bruce Willis as a child psychologist?", options: ["Die Hard", "The Sixth Sense", "Unbreakable"], answer: "The Sixth Sense" },
+// { question: "In 'The Matrix', does Neo take the blue pill or the red pill?", options: ["Blue", "Red", "Green"], answer: "Red" },
+// { question: "Which actress played Katniss Everdeen in 'The Hunger Games' movies?", options: ["Jennifer Lawrence", "Emma Watson", "Shailene Woodley"], answer: "Jennifer Lawrence" },
+// { question: "Who directed 'Jurassic Park'?", options: ["James Cameron", "Steven Spielberg", "George Lucas"], answer: "Steven Spielberg" },
+// { question: "What 1980s movie was the highest grossing film of the decade?", options: ["E.T. the Extra-Terrestrial", "Star Wars: Episode V", "Back to the Future"], answer: "E.T. the Extra-Terrestrial" },
+// { question: "Which movie features the song 'My Heart Will Go On'?", options: ["The Bodyguard", "Titanic", "Romeo + Juliet"], answer: "Titanic" },
+// { question: "What was the first Pixar movie?", options: ["Toy Story", "A Bug's Life", "Monsters, Inc."], answer: "Toy Story" },
+// { question: "Who played Wolverine in the X-Men movies?", options: ["Hugh Jackman", "Liam Hemsworth", "Chris Evans"], answer: "Hugh Jackman" },
+// { question: "Which film did NOT win the Academy Award for Best Picture?", options: ["The Shawshank Redemption", "The Godfather", "Forrest Gump"], answer: "The Shawshank Redemption" },
+// { question: "What is Indiana Jones' real first name?", options: ["Henry", "John", "Walter"], answer: "Henry" },
+// { question: "In 'The Wizard of Oz', what did the Scarecrow want from the wizard?", options: ["Heart", "Brain", "Courage"], answer: "Brain" },
+// { question: "Who is the only actor to receive an Oscar nomination for acting in a Lord of the Rings movie?", options: ["Viggo Mortensen", "Ian McKellen", "Elijah Wood"], answer: "Ian McKellen" },
+// { question: "Which movie features an iconic dance scene between Uma Thurman and John Travolta?", options: ["Pulp Fiction", "Kill Bill", "Saturday Night Fever"], answer: "Pulp Fiction" },
+// { question: "What is the highest-grossing R-rated movie of all time?", options: ["Deadpool", "Joker", "The Matrix"], answer: "Joker" },
+// { question: "Which Alfred Hitchcock movie is notorious for its shower scene?", options: ["Vertigo", "Psycho", "Rear Window"], answer: "Psycho" },
+// { question: "What is Darth Vader's real name?", options: ["Anakin Skywalker", "Luke Skywalker", "Obi-Wan Kenobi"], answer: "Anakin Skywalker" },
+// { question: "Who directed 'Schindler's List'?", options: ["Martin Scorsese", "Steven Spielberg", "Ridley Scott"], answer: "Steven Spielberg" },
+// { question: "In which movie does Tom Cruise perform his own stunts climbing the Burj Khalifa?", options: ["Mission: Impossible - Rogue Nation", "Mission: Impossible - Ghost Protocol", "Edge of Tomorrow"], answer: "Mission: Impossible - Ghost Protocol" },
+// { question: "What is the name of the fictional African country where 'Black Panther' is set?", options: ["Wakanda", "Genovia", "Zamunda"], answer: "Wakanda" },
+// { question: "Who directed 'Inception' and 'Interstellar'?", options: ["Christopher Nolan", "James Cameron", "Steven Spielberg"], answer: "Christopher Nolan" },
+// { question: "In 'The Hunger Games', what district do Katniss and Peeta represent?", options: ["District 12", "District 9", "District 7"], answer: "District 12" },
+// { question: "Which movie features a character named Tyler Durden?", options: ["Fight Club", "Gone Girl", "Seven"], answer: "Fight Club" },
+// { question: "What is the name of the island in 'Jurassic Park'?", options: ["Isla Nublar", "Isla Sorna", "Skull Island"], answer: "Isla Nublar" },
+// { question: "Who played the Joker in 'The Dark Knight'?", options: ["Heath Ledger", "Joaquin Phoenix", "Jared Leto"], answer: "Heath Ledger" },
+// { question: "In which movie is the fictional company Initech featured?", options: ["Office Space", "The Social Network", "Wall Street"], answer: "Office Space" },
+// { question: "What year was the first 'Harry Potter' movie released?", options: ["2001", "2003", "1999"], answer: "2001" },
+// { question: "What fictional country is 'Wonder Woman' from?", options: ["Themyscira", "Asgard", "Genovia"], answer: "Themyscira" },
+// { question: "Which movie is known for the quote 'Here's looking at you, kid'?", options: ["Casablanca", "Gone with the Wind", "The Maltese Falcon"], answer: "Casablanca" },
+// { question: "In 'The Lion King', what is Simba's mother's name?", options: ["Nala", "Sarabi", "Shenzi"], answer: "Sarabi" },
+// { question: "Who directed 'Avengers: Endgame'?", options: ["The Russo Brothers", "Joss Whedon", "Jon Favreau"], answer: "The Russo Brothers" },
+// { question: "What is the name of the kingdom in 'Tangled'?", options: ["Corona", "Far Far Away", "Arendelle"], answer: "Corona" },
+// { question: "Which film features a famous dance scene with Uma Thurman and John Travolta?", options: ["Pulp Fiction", "Saturday Night Fever", "Kill Bill"], answer: "Pulp Fiction" },
+// { question: "Who played Jack Dawson in 'Titanic'?", options: ["Leonardo DiCaprio", "Brad Pitt", "Johnny Depp"], answer: "Leonardo DiCaprio" },
+// { question: "What is the highest-grossing film of all time?", options: ["Avengers: Endgame", "Avatar", "Titanic"], answer: "Avatar" },
+// { question: "In which movie does the character Neo appear?", options: ["The Matrix", "John Wick", "Speed"], answer: "The Matrix" },
+// { question: "What is the real name of the Black Panther in the Marvel Cinematic Universe?", options: ["T'Challa", "M'Baku", "N'Jadaka"], answer: "T'Challa" },
+// { question: "Who directed 'Mad Max: Fury Road'?", options: ["George Miller", "Ridley Scott", "Peter Jackson"], answer: "George Miller" },
+// { question: "What animated film features a character named 'Hiccup'?", options: ["Brave", "How to Train Your Dragon", "Shrek"], answer: "How to Train Your Dragon" },
+// { question: "In which film is the fictional mineral 'Unobtainium' sought after?", options: ["Avatar", "The Core", "Transformers"], answer: "Avatar" },
+// ];
+
+ // Trivia Data
+ private var questions: [TriviaQuestion] = [
+ TriviaQuestion(question: "What movie won the Academy Award for Best Picture in 2020?", options: ["Joker", "1917", "Parasite"], correctAnswer: "Parasite"),
+ TriviaQuestion(question: "Who directed the movie 'The Godfather'?", options: ["Steven Spielberg", "Francis Ford Coppola", "Martin Scorsese"], correctAnswer: "Francis Ford Coppola"),
+ TriviaQuestion(question: "What was the first feature-length animated movie ever released?", options: ["Snow White and the Seven Dwarfs", "Bambi", "Pinocchio"], correctAnswer: "Snow White and the Seven Dwarfs"),
+ TriviaQuestion(question: "What was the highest-grossing movie of all time before the release of 'Avatar'?", options: ["Titanic", "Star Wars: The Force Awakens", "Avengers: Endgame"], correctAnswer: "Titanic"),
+ TriviaQuestion(question: "Who played the lead role in the movie 'Forrest Gump'?", options: ["Tom Hanks", "Brad Pitt", "Leonardo DiCaprio"], correctAnswer: "Tom Hanks"),
+ TriviaQuestion(question: "What movie won the Academy Award for Best Picture in 2019?", options: ["Bohemian Rhapsody", "Green Book", "Roma"], correctAnswer: "Green Book"),
+ TriviaQuestion(question: "Who played the character of John McClane in the Die Hard movie series?", options: ["Arnold Schwarzenegger", "Sylvester Stallone", "Bruce Willis"], correctAnswer: "Bruce Willis"),
+ TriviaQuestion(question: "What movie is based on a novel by Stephen King and features a character named Jack Torrance?", options: ["Carrie", "The Shining", "Misery"], correctAnswer: "The Shining"),
+ TriviaQuestion(question: "Who directed the movie 'Forrest Gump'?", options: ["Steven Spielberg", "Robert Zemeckis", "Martin Scorsese"], correctAnswer: "Robert Zemeckis"),
+ TriviaQuestion(question: "What is the highest-grossing movie of all time (as of 2021)?", options: ["Avatar", "Avengers: Endgame", "Titanic"], correctAnswer: "Avatar"),
+ ]
+
+ private var currentQuestionIndex = 0
+ private var score = 0
+
+ // UI Components
+ private let questionLabel: UILabel = {
+ let label = UILabel()
+ label.font = UIFont.systemFont(ofSize: 20)
+ label.numberOfLines = 0
+ label.textAlignment = .center
+ return label
+ }()
+
+ private var optionButtons: [UIButton] = []
+
+ // MARK: - Lifecycle
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupUI()
+ loadQuestion()
+ }
+
+ // MARK: - Setup
+ private func setupUI() {
+ view.backgroundColor = .white
+ view.addSubview(questionLabel)
+
+ setupOptionButtons()
+ layoutUI()
+ title = "Movie Trivia"
+ }
+
+ private func setupOptionButtons() {
+ for _ in 1...4 {
+ let button = UIButton(type: .system)
+ button.titleLabel?.font = UIFont.systemFont(ofSize: 18)
+ button.addTarget(self, action: #selector(optionButtonTapped), for: .touchUpInside)
+ optionButtons.append(button)
+ view.addSubview(button)
+ }
+ }
+
+ private func layoutUI() {
+ questionLabel.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ questionLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
+ questionLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
+ questionLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
+ ])
+
+ var previousButton: UIButton?
+ for button in optionButtons {
+ button.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ button.topAnchor.constraint(equalTo: previousButton?.bottomAnchor ?? questionLabel.bottomAnchor, constant: 20),
+ button.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
+ button.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
+ ])
+ previousButton = button
+ }
+ }
+
+ // MARK: - Actions
+ @objc private func optionButtonTapped(_ sender: UIButton) {
+ guard let answer = sender.titleLabel?.text else { return }
+ checkAnswer(answer)
+ }
+
+ // MARK: - Trivia Logic
+ private func loadQuestion() {
+ guard currentQuestionIndex < questions.count else {
+ // Show results
+ showResults()
+ return
+ }
+
+ let currentQuestion = questions[currentQuestionIndex]
+ questionLabel.text = currentQuestion.question
+
+ for (index, button) in optionButtons.enumerated() {
+ button.setTitle(currentQuestion.options[index], for: .normal)
+ }
+ }
+
+ private func checkAnswer(_ answer: String) {
+ let currentQuestion = questions[currentQuestionIndex]
+ if answer == currentQuestion.correctAnswer {
+ score += 1
+ }
+
+ currentQuestionIndex += 1
+ loadQuestion()
+ }
+
+ private func showResults() {
+ let alertController = UIAlertController(title: "Trivia Complete", message: "Your score: \(score)/\(questions.count)", preferredStyle: .alert)
+ let action = UIAlertAction(title: "OK", style: .default) { _ in
+ self.navigationController?.popViewController(animated: true)
+ }
+ alertController.addAction(action)
+ present(alertController, animated: true)
+ }
+}
diff --git a/MovieVerse-Mobile/app/ios/SearchViewController.swift b/MovieVerse-Mobile/app/ios/SearchViewController.swift
new file mode 100644
index 00000000..08811dbe
--- /dev/null
+++ b/MovieVerse-Mobile/app/ios/SearchViewController.swift
@@ -0,0 +1,90 @@
+import UIKit
+
+struct Movie {
+ let title: String
+ let releaseYear: String
+ let description: String
+ let posterURL: String
+}
+
+class SearchViewController: UIViewController, UISearchBarDelegate {
+
+ private let searchBar: UISearchBar = {
+ let searchBar = UISearchBar()
+ searchBar.placeholder = "Search Movies"
+ return searchBar
+ }()
+
+ private var movies: [Movie] = []
+
+ private let tableView: UITableView = {
+ let table = UITableView()
+ table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
+ return table
+ }()
+
+ // MARK: - Lifecycle
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ setupUI()
+ configureTableView()
+ }
+
+ // MARK: - Setup
+ private func setupUI() {
+ view.backgroundColor = .white
+ searchBar.delegate = self
+ navigationItem.titleView = searchBar
+ view.addSubview(tableView)
+ layoutUI()
+ }
+
+ private func configureTableView() {
+ tableView.dataSource = self
+ tableView.delegate = self
+ }
+
+ private func layoutUI() {
+ tableView.translatesAutoresizingMaskIntoConstraints = false
+ NSLayoutConstraint.activate([
+ tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0),
+ tableView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0),
+ tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor, constant: 0),
+ tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor, constant: 0)
+ ])
+ searchedMoviesLabel.translatesAutoresizingMaskIntoConstraints = false
+ resultsLabel.translatesAutoresizingMaskIntoConstraints = false
+ }
+
+ // MARK: - UISearchBarDelegate
+ func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
+ guard let query = searchBar.text, !query.isEmpty else { return }
+ searchMovies(query: query)
+ }
+
+ private func searchMovies(query: String) {
+ tableView.isHidden = false
+ movies = [] // Reset movies
+ movies = MovieService.shared.searchMovies(query: query)
+ tableView.reloadData()
+ }
+}
+
+// MARK: - UITableViewDataSource, UITableViewDelegate
+extension SearchViewController: UITableViewDataSource, UITableViewDelegate {
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return movies.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
+ cell.textLabel?.text = movies[indexPath.row].title
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ tableView.deselectRow(at: indexPath, animated: true)
+ movieDetails(movie: movies[indexPath.row])
+ }
+}
diff --git a/MovieVerse-Mobile/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist b/MovieVerse-Mobile/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 00000000..33ba33c2
--- /dev/null
+++ b/MovieVerse-Mobile/platforms/ios/CordovaLib/CordovaLib.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,19 @@
+
+
+
+
+ SchemeUserState
+
+ Cordova.xcscheme_^#shared#^_
+
+ orderHint
+ 2
+
+ CordovaLib.xcscheme_^#shared#^_
+
+ orderHint
+ 1
+
+
+
+
diff --git a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate
deleted file mode 100644
index c4cf6050..00000000
Binary files a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/project.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ
diff --git a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 00000000..a395af29
Binary files /dev/null and b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist
similarity index 93%
rename from MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist
rename to MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist
index 880664ff..e72660e6 100644
--- a/MovieVerse-Mobile/platforms/ios/MovieVerse.xcodeproj/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/MovieVerse-Mobile/platforms/ios/MovieVerse.xcworkspace/xcuserdata/davidnguyen.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,7 +7,7 @@
MovieVerse.xcscheme_^#shared#^_
orderHint
- 2
+ 0
diff --git a/MovieVerse-Mobile/platforms/ios/www/movie-timeline.html b/MovieVerse-Mobile/platforms/ios/www/movie-timeline.html
new file mode 100644
index 00000000..f9afa9a7
--- /dev/null
+++ b/MovieVerse-Mobile/platforms/ios/www/movie-timeline.html
@@ -0,0 +1,53 @@
+
+
+
+
+ Movie Timeline
+
+
+
+
+
+
+
+
+ The Movie Timeline
+
+ Home
+ Favorites
+
+
+
+
+Movie of the Day
+
+
+MovieVerse Chatbot
+
+
+Trivia Game
+
+
+
+
diff --git a/MovieVerse-Mobile/platforms/ios/www/movie-timeline.js b/MovieVerse-Mobile/platforms/ios/www/movie-timeline.js
new file mode 100644
index 00000000..d206acbb
--- /dev/null
+++ b/MovieVerse-Mobile/platforms/ios/www/movie-timeline.js
@@ -0,0 +1,191 @@
+document.getElementById('load-movies').addEventListener('click', updateMovies);
+document.getElementById('start-year').addEventListener('keypress', function(event) {
+ if (event.keyCode === 13) {
+ updateMovies();
+ }
+});
+
+document.getElementById('end-year').addEventListener('keypress', function(event) {
+ if (event.keyCode === 13) {
+ updateMovies();
+ }
+});
+
+const IMGPATH = "https://image.tmdb.org/t/p/w1280";
+const SEARCHPATH = "https://api.themoviedb.org/3/search/movie?&api_key=c5a20c861acf7bb8d9e987dcc7f1b558&query=";
+const searchTitle = document.getElementById("select-text");
+const searchButton = document.getElementById("button-search");
+const search = document.getElementById("search");
+const main = document.getElementById("movies-container");
+
+async function getMovies(url) {
+ clearMovieDetails();
+ const numberOfMovies = calculateMoviesToDisplay();
+ const pagesToFetch = numberOfMovies <= 20 ? 1 : 2;
+ let allMovies = [];
+ for (let page = 1; page <= pagesToFetch; page++) {
+ const response = await fetch(`${url}&page=${page}`);
+ const data = await response.json();
+ allMovies = allMovies.concat(data.results);
+ }
+ allMovies.sort((a, b) => b.vote_average - a.vote_average);
+ if (allMovies.length > 0) {
+ showMovies(allMovies.slice(0, numberOfMovies), main);
+ }
+ else {
+ main.innerHTML = `No movie with the specified search term found. Please try again.
`;
+ }
+}
+
+function clearMovieDetails() {
+ const movieDetailsContainer = document.getElementById('movie-details-container');
+ if (movieDetailsContainer) {
+ movieDetailsContainer.innerHTML = '';
+ }
+}
+
+form.addEventListener('submit', (e) => {
+ e.preventDefault();
+ const searchTerm = search.value.trim();
+ if (searchTerm) {
+ getMovies(SEARCHPATH + searchTerm);
+ searchTitle.innerHTML = 'Search Results for: ' + searchTerm;
+ search.value = '';
+ }
+ else {
+ searchTitle.innerHTML = 'Please enter a search term.';
+ }
+ document.getElementById('clear-search-btn').style.display = 'block';
+});
+
+searchButton.addEventListener('click', (e) => {
+ e.preventDefault();
+ const searchTerm = search.value;
+ if (searchTerm) {
+ getMovies(SEARCHPATH + searchTerm);
+ searchTitle.innerHTML = 'Search Results for: ' + searchTerm;
+ search.value = '';
+ }
+ else {
+ searchTitle.innerHTML = 'Please enter a search term.';
+ }
+ document.getElementById('clear-search-btn').style.display = 'block';
+});
+
+function updateMovies() {
+ let startYear = document.getElementById('start-year').value;
+ let endYear = document.getElementById('end-year').value;
+ let currentYear = new Date().getFullYear();
+ if (startYear && endYear && startYear <= endYear && endYear <= currentYear) {
+ fetchMoviesByTimePeriod(startYear, endYear);
+ }
+ else {
+ alert('Please ensure the start year is before the end year, and both are not later than the current year.');
+ }
+}
+
+function showMovies(movies, mainElement) {
+ mainElement.innerHTML = '';
+ movies.forEach(movie => {
+ const movieEl = document.createElement('div');
+ movieEl.classList.add('movie');
+ const movieImage = movie.poster_path
+ ? ` `
+ : `Image Not Available
`;
+ const voteAvg = movie.vote_average.toFixed(1);
+ const ratingClass = getClassByRate(movie.vote_average);
+ movieEl.innerHTML = `
+ ${movieImage}
+
+
${movie.title}
+ ${voteAvg}
+
+
+
Movie Intro:
+ ${movie.overview}
+ `;
+ movieEl.addEventListener('click', () => {
+ localStorage.setItem('selectedMovieId', movie.id);
+ window.location.href = 'movie-details.html';
+ });
+ movieEl.style.cursor = 'pointer';
+ mainElement.appendChild(movieEl);
+ });
+}
+
+document.getElementById('clear-search-btn').addEventListener('click', () => {
+ location.reload();
+});
+
+async function fetchMoviesByTimePeriod(startYear, endYear) {
+ const url = `https://api.themoviedb.org/3/discover/movie?api_key=c5a20c861acf7bb8d9e987dcc7f1b558&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31`;
+ const response = await fetch(url);
+ const data = await response.json();
+ const numberOfMovies = calculateMoviesToDisplay();
+ const moviesToShow = data.results.slice(0, numberOfMovies);
+ showMovies(moviesToShow, document.getElementById('movies-container'));
+}
+
+document.getElementById('load-movies').addEventListener('click', () => {
+ const startYear = document.getElementById('start-year').value;
+ const endYear = document.getElementById('end-year').value;
+ fetchMoviesByTimePeriod(startYear, endYear);
+});
+
+function calculateMoviesToDisplay() {
+ const screenWidth = window.innerWidth;
+ if (screenWidth <= 689.9) return 10; // 1 movie per row
+ if (screenWidth <= 1021.24) return 20; // 2 movies per row
+ if (screenWidth <= 1353.74) return 21; // 3 movies per row
+ if (screenWidth <= 1684.9) return 20; // 4 movies per row
+ if (screenWidth <= 2017.49) return 20; // 5 movies per row
+ if (screenWidth <= 2349.99) return 18; // 6 movies per row
+ if (screenWidth <= 2681.99) return 21; // 7 movies per row
+ if (screenWidth <= 3014.49) return 24; // 8 movies per row
+ if (screenWidth <= 3345.99) return 27; // 9 movies per row
+ if (screenWidth <= 3677.99) return 20; // 10 movies per row
+ if (screenWidth <= 4009.99) return 22; // 11 movies per row
+ if (screenWidth <= 4340.99) return 24; // 12 movies per row
+ if (screenWidth <= 4673.49) return 26; // 13 movies per row
+ if (screenWidth <= 5005.99) return 28; // 14 movies per row
+ if (screenWidth <= 5337.99) return 30; // 15 movies per row
+ if (screenWidth <= 5669.99) return 32; // 16 movies per row
+ if (screenWidth <= 6001.99) return 34; // 17 movies per row
+ if (screenWidth <= 6333.99) return 36; // 18 movies per row
+ if (screenWidth <= 6665.99) return 38; // 19 movies per row
+ if (screenWidth <= 6997.99) return 40; // 20 movies per row
+ if (screenWidth <= 7329.99) return 42; // 21 movies per row
+ if (screenWidth <= 7661.99) return 44; // 22 movies per row
+ if (screenWidth <= 7993.99) return 46; // 23 movies per row
+ if (screenWidth <= 8325.99) return 48; // 24 movies per row
+ return 20;
+}
+
+function getClassByRate(vote) {
+ if (vote >= 8) {
+ return 'green';
+ }
+ else if (vote >= 5) {
+ return 'orange';
+ }
+ else {
+ return 'red';
+ }
+}
+
+async function showMovieOfTheDay(){
+ const year = new Date().getFullYear();
+ const url = `https://api.themoviedb.org/3/discover/movie?api_key=c5a20c861acf7bb8d9e987dcc7f1b558&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`;
+ try {
+ const response = await fetch(url);
+ const data = await response.json();
+ const movies = data.results;
+ const randomMovie = movies[Math.floor(Math.random() * movies.length)];
+ localStorage.setItem('selectedMovieId', randomMovie.id);
+ window.location.href = 'movie-details.html';
+ }
+ catch (error) {
+ console.error('Error fetching movie:', error);
+ alert('Failed to fetch the movie of the day. Please try again later.');
+ }
+}
diff --git a/MovieVerse-Mobile/www/about.html b/MovieVerse-Mobile/www/about.html
index d1de90eb..1acf696a 100644
--- a/MovieVerse-Mobile/www/about.html
+++ b/MovieVerse-Mobile/www/about.html
@@ -6,6 +6,7 @@
+
diff --git a/MovieVerse-Mobile/www/app.js b/MovieVerse-Mobile/www/app.js
index 3f9deeab..e7daefb6 100644
--- a/MovieVerse-Mobile/www/app.js
+++ b/MovieVerse-Mobile/www/app.js
@@ -1,13 +1,11 @@
const chatbotInput = document.getElementById("chatbotInput");
const chatbotBody = document.getElementById("chatbotBody");
+let initialMainContent;
document.addEventListener('DOMContentLoaded', function() {
- chatbotInput.addEventListener("keydown", function(event) {
- if (event.key === "Enter") {
- sendMessage(chatbotInput.value);
- chatbotInput.value = "";
- }
- });
+ initialMainContent = document.getElementById('main').innerHTML;
+ initializeChatbot();
+ document.getElementById('clear-search-btn').style.display = 'none';
});
function sendMessage(message) {
@@ -17,15 +15,185 @@ function sendMessage(message) {
let botReply = movieVerseResponse(message); // Renamed function for clarity
setTimeout(() => {
chatbotBody.innerHTML += `
- Assistant: ${botReply}
+ MovieVerse Assistant: ${botReply}
`;
}, 1000);
}
+const search = document.getElementById("search");
+const searchButton = document.getElementById("button-search");
+const searchTitle = document.getElementById("search-title");
+const otherTitle = document.getElementById("other1");
+const SEARCHPATH = "https://api.themoviedb.org/3/search/movie?&api_key=c5a20c861acf7bb8d9e987dcc7f1b558&query=";
+const IMGPATH = "https://image.tmdb.org/t/p/w1280";
+const main = document.getElementById("main");
+
+function calculateMoviesToDisplay() {
+ const screenWidth = window.innerWidth;
+ if (screenWidth <= 689.9) return 10; // 1 movie per row
+ if (screenWidth <= 1021.24) return 20; // 2 movies per row
+ if (screenWidth <= 1353.74) return 21; // 3 movies per row
+ if (screenWidth <= 1684.9) return 20; // 4 movies per row
+ if (screenWidth <= 2017.49) return 20; // 5 movies per row
+ if (screenWidth <= 2349.99) return 18; // 6 movies per row
+ if (screenWidth <= 2681.99) return 21; // 7 movies per row
+ if (screenWidth <= 3014.49) return 24; // 8 movies per row
+ if (screenWidth <= 3345.99) return 27; // 9 movies per row
+ if (screenWidth <= 3677.99) return 20; // 10 movies per row
+ if (screenWidth <= 4009.99) return 22; // 11 movies per row
+ if (screenWidth <= 4340.99) return 24; // 12 movies per row
+ if (screenWidth <= 4673.49) return 26; // 13 movies per row
+ if (screenWidth <= 5005.99) return 28; // 14 movies per row
+ if (screenWidth <= 5337.99) return 30; // 15 movies per row
+ if (screenWidth <= 5669.99) return 32; // 16 movies per row
+ if (screenWidth <= 6001.99) return 34; // 17 movies per row
+ if (screenWidth <= 6333.99) return 36; // 18 movies per row
+ if (screenWidth <= 6665.99) return 38; // 19 movies per row
+ if (screenWidth <= 6997.99) return 40; // 20 movies per row
+ if (screenWidth <= 7329.99) return 42; // 21 movies per row
+ if (screenWidth <= 7661.99) return 44; // 22 movies per row
+ if (screenWidth <= 7993.99) return 46; // 23 movies per row
+ if (screenWidth <= 8325.99) return 48; // 24 movies per row
+ return 20;
+}
+
+function initializeChatbot() {
+ // Getting elements that may have been reloaded in the DOM
+ const chatbotInput = document.getElementById("chatbotInput");
+ const chatbotBody = document.getElementById("chatbotBody");
+
+ // Reattaching the event listener for Enter key on chatbot input
+ chatbotInput.addEventListener("keydown", function(event) {
+ if (event.key === "Enter") {
+ sendMessage(chatbotInput.value);
+ chatbotInput.value = "";
+ }
+ });
+
+ // Define the sendMessage function inside initializeChatbot to ensure scope
+ function sendMessage(message) {
+ chatbotBody.innerHTML += `
+ You: ${message}
+ `;
+ let botReply = movieVerseResponse(message);
+ setTimeout(() => {
+ chatbotBody.innerHTML += `
+ MovieVerse Assistant: ${botReply}
+ `;
+ }, 1000);
+ }
+}
+
+function showMovies(movies, mainElement) {
+ mainElement.innerHTML = '';
+ movies.forEach(movie => {
+ const { id, poster_path, title, vote_average, overview } = movie;
+ const movieEl = document.createElement('div');
+ movieEl.classList.add('movie');
+ const movieImage = poster_path
+ ? ` `
+ : `Image Not Available
`;
+
+ const voteAvg = vote_average.toFixed(1);
+ movieEl.innerHTML = `
+ ${movieImage}
+
+
${title}
+ ${voteAvg}
+
+
+
Movie Intro:
+ ${overview}
+ `;
+
+ movieEl.addEventListener('click', () => {
+ localStorage.setItem('selectedMovieId', id);
+ window.location.href = 'movie-details.html';
+ });
+
+ mainElement.appendChild(movieEl);
+ });
+}
+
+function getClassByRate(vote){
+ if (vote >= 8) {
+ return 'green';
+ }
+ else if (vote >= 5) {
+ return 'orange';
+ }
+ else {
+ return 'red';
+ }
+}
+
+async function getMovies(url, mainElement) {
+ clearMovieDetails();
+ const numberOfMovies = calculateMoviesToDisplay();
+ const pagesToFetch = numberOfMovies <= 20 ? 1 : 2;
+ let allMovies = [];
+ for (let page = 1; page <= pagesToFetch; page++) {
+ const response = await fetch(`${url}&page=${page}`);
+ const data = await response.json();
+ allMovies = allMovies.concat(data.results);
+ }
+ allMovies.sort((a, b) => b.vote_average - a.vote_average);
+ if (allMovies.length > 0) {
+ showMovies(allMovies.slice(0, numberOfMovies), mainElement);
+ document.getElementById('clear-search-btn').style.display = 'inline-block'; // Show the button
+ }
+ else {
+ mainElement.innerHTML = `No movie with the specified search term found. Please try again.
`;
+ document.getElementById('clear-search-btn').style.display = 'none'; // Hide the button if no results
+ }
+ document.getElementById('alt-title').innerHTML = '';
+}
+
+document.getElementById('clear-search-btn').addEventListener('click', function() {
+ document.getElementById('main').innerHTML = initialMainContent;
+ initializeChatbot(); // Re-initialize chatbot after restoring content
+ searchTitle.innerHTML = '';
+ this.style.display = 'none';
+});
+
+form.addEventListener('submit', (e) => {
+ e.preventDefault();
+ const searchTerm = search.value.trim();
+ if (searchTerm) {
+ getMovies(SEARCHPATH + searchTerm, main);
+ searchTitle.innerHTML = 'Search Results for: ' + searchTerm;
+ otherTitle.innerHTML = 'Check out other movies, too:';
+ search.value = '';
+ }
+ else {
+ searchTitle.innerHTML = 'Please enter a search term.';
+ }
+});
+
+searchButton.addEventListener('click', (e) => {
+ e.preventDefault();
+ const searchTerm = search.value;
+ if (searchTerm) {
+ getMovies(SEARCHPATH + searchTerm, main);
+ searchTitle.innerHTML = 'Search Results for: ' + searchTerm;
+ otherTitle.innerHTML = 'Check out other movies:';
+ search.value = '';
+ }
+ else {
+ searchTitle.innerHTML = 'Please enter a search term.';
+ }
+});
+
+function clearMovieDetails() {
+ const movieDetailsContainer = document.getElementById('main');
+ if (movieDetailsContainer) {
+ movieDetailsContainer.innerHTML = '';
+ }
+}
+
function movieVerseResponse(message) {
const lowerMessage = message.toLowerCase();
-
- if (lowerMessage.includes("hello") || lowerMessage.includes("hi")) {
+ if (lowerMessage.includes("hello") || lowerMessage.includes("hi") || lowerMessage.includes("hey")) {
return "Hello! How can I assist you with MovieVerse today?";
} else if (lowerMessage.includes("how are you")) {
return "I'm your digital MovieVerse assistant, ready to help! How can I assist you with movie info?";
@@ -143,8 +311,57 @@ function movieVerseResponse(message) {
return "Of course! Let me know your favorite director, and I'll suggest a movie accordingly!";
} else if (lowerMessage.includes("movie suggestions based on year")) {
return "Of course! Let me know your favorite year, and I'll suggest a movie accordingly!";
- }
- else {
+ } else if (lowerMessage.includes("movie") || lowerMessage.includes("movies")) {
+ return "You can search for a movie using the search field above!";
+ } else if (lowerMessage.includes("1900s")) {
+ return "Movies in the 1900s include: A Trip to the Moon, The Great Train Robbery, etc.";
+ } else if (lowerMessage.includes("1910s")) {
+ return "Movies in the 1910s include: The Birth of a Nation, Intolerance, etc.";
+ } else if (lowerMessage.includes("1920s")) {
+ return "Movies in the 1920s include: The Kid, The Gold Rush, etc.";
+ } else if (lowerMessage.includes("1930s")) {
+ return "Movies in the 1930s include: King Kong, Snow White and the Seven Dwarfs, etc.";
+ } else if (lowerMessage.includes("1940s")) {
+ return "Movies in the 1940s include: Citizen Kane, Casablanca, etc.";
+ } else if (lowerMessage.includes("1950s")) {
+ return "Movies in the 1950s include: Sunset Boulevard, Singin' in the Rain, etc.";
+ } else if (lowerMessage.includes("1960s")) {
+ return "Movies in the 1960s include: Psycho, The Apartment, etc.";
+ } else if (lowerMessage.includes("1970s")) {
+ return "Movies in the 1970s include: The Godfather, Star Wars, etc.";
+ } else if (lowerMessage.includes("1980s")) {
+ return "Movies in the 1980s include: Back to the Future, The Shining, etc.";
+ } else if (lowerMessage.includes("1990s")) {
+ return "Movies in the 1990s include: The Silence of the Lambs, Titanic, etc.";
+ } else if (lowerMessage.includes("2000s")) {
+ return "Movies in the 2000s include: The Lord of the Rings: The Return of the King, The Dark Knight, etc.";
+ } else if (lowerMessage.includes("2010s")) {
+ return "Movies in the 2010s include: Inception, The Avengers, etc.";
+ } else if (lowerMessage.includes("2020s")) {
+ return "Movies in the 2020s include: Tenet, Soul, etc.";
+ } else if (lowerMessage.includes("2022")) {
+ return "Movies in 2022 include: Thor: Love and Thunder, Doctor Strange in the Multiverse of Madness, etc.";
+ } else if (lowerMessage.includes("2023")) {
+ return "Movies in 2023 include: The Flash, Black Panther: Wakanda Forever, etc.";
+ } else {
return "Sorry, I didn't catch that. Can you rephrase or ask another question about movies?";
}
}
+
+async function showMovieOfTheDay() {
+ const year = new Date().getFullYear();
+ const url = `https://api.themoviedb.org/3/discover/movie?api_key=c5a20c861acf7bb8d9e987dcc7f1b558&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`;
+ try {
+ const response = await fetch(url);
+ const data = await response.json();
+ const movies = data.results;
+ const randomMovie = movies[Math.floor(Math.random() * movies.length)];
+
+ localStorage.setItem('selectedMovieId', randomMovie.id);
+ window.location.href = 'movie-details.html';
+ }
+ catch (error) {
+ console.error('Error fetching movie:', error);
+ alert('Failed to fetch the movie of the day. Please try again later.');
+ }
+}
diff --git a/MovieVerse-Mobile/www/director-details.html b/MovieVerse-Mobile/www/director-details.html
index bad693a0..ab067661 100644
--- a/MovieVerse-Mobile/www/director-details.html
+++ b/MovieVerse-Mobile/www/director-details.html
@@ -6,6 +6,7 @@
+
diff --git a/MovieVerse-Mobile/www/discussions.css b/MovieVerse-Mobile/www/discussions.css
index 10e34d4e..89878da7 100644
--- a/MovieVerse-Mobile/www/discussions.css
+++ b/MovieVerse-Mobile/www/discussions.css
@@ -14,6 +14,7 @@ body {
background-size: cover;
background-position: center;
background-repeat: no-repeat;
+ background-attachment: fixed;
overflow: hidden;
height: 100%;
}
@@ -256,4 +257,38 @@ ol li:hover {
position: fixed;
top: 20px;
right: -30px;
-}
\ No newline at end of file
+}
+
+#movie-timeline-btn {
+ position: fixed;
+ bottom: 180px;
+ right: 30px;
+ background-color: #7378c5;
+ font: inherit;
+ color: black;
+ border-radius: 8px;
+ border: none;
+ cursor: pointer;
+}
+
+#movie-timeline-btn:hover {
+ background-color: #ff8623;
+ transition: 0.3s ease-in;
+}
+
+#movie-of-the-day-btn {
+ position: fixed;
+ bottom: 140px;
+ right: 30px;
+ background-color: #7378c5;
+ font: inherit;
+ color: black;
+ border-radius: 8px;
+ border: none;
+ cursor: pointer;
+}
+
+#movie-of-the-day-btn:hover {
+ background-color: #ff8623;
+ transition: 0.1s linear;
+}
diff --git a/MovieVerse-Mobile/www/discussions.html b/MovieVerse-Mobile/www/discussions.html
index 181c6f10..9db62698 100644
--- a/MovieVerse-Mobile/www/discussions.html
+++ b/MovieVerse-Mobile/www/discussions.html
@@ -11,26 +11,35 @@
-
-
+
+
+
+
+
+
Home
About
Favorites
- MovieVerse Chatbot
- Trivia Game
- Welcome to the MovieVerse Chatbot!
-
+
+
+
-
- The MovieVerse Assistant
- Here, you can ask the chatbot about any movie-related topics or questions!
+
@@ -41,6 +50,10 @@
Here, you can ask the chatbot about any movie-related topics or questions!
+Movie Timeline
+Movie of the Day
+Trivia Game
+
Back To Main Page
diff --git a/MovieVerse-Mobile/www/index.html b/MovieVerse-Mobile/www/index.html
index d9c7f460..0d0212d3 100644
--- a/MovieVerse-Mobile/www/index.html
+++ b/MovieVerse-Mobile/www/index.html
@@ -285,6 +285,8 @@ Trending CLASSIC Movies:
+ Movie Timeline
+
Movie of the Day
diff --git a/MovieVerse-Mobile/www/movie-details.html b/MovieVerse-Mobile/www/movie-details.html
index 2249feda..b40ec7cc 100644
--- a/MovieVerse-Mobile/www/movie-details.html
+++ b/MovieVerse-Mobile/www/movie-details.html
@@ -5,6 +5,7 @@
Movie Details
+
diff --git a/MovieVerse-Mobile/www/movie-timeline.html b/MovieVerse-Mobile/www/movie-timeline.html
new file mode 100644
index 00000000..f9afa9a7
--- /dev/null
+++ b/MovieVerse-Mobile/www/movie-timeline.html
@@ -0,0 +1,53 @@
+
+
+
+
+ Movie Timeline
+
+
+
+
+
+
+
+
+ The Movie Timeline
+
+ Home
+ Favorites
+
+
+
+
+Movie of the Day
+
+
+MovieVerse Chatbot
+
+
+Trivia Game
+
+
+
+
diff --git a/MovieVerse-Mobile/www/movie-timeline.js b/MovieVerse-Mobile/www/movie-timeline.js
new file mode 100644
index 00000000..d206acbb
--- /dev/null
+++ b/MovieVerse-Mobile/www/movie-timeline.js
@@ -0,0 +1,191 @@
+document.getElementById('load-movies').addEventListener('click', updateMovies);
+document.getElementById('start-year').addEventListener('keypress', function(event) {
+ if (event.keyCode === 13) {
+ updateMovies();
+ }
+});
+
+document.getElementById('end-year').addEventListener('keypress', function(event) {
+ if (event.keyCode === 13) {
+ updateMovies();
+ }
+});
+
+const IMGPATH = "https://image.tmdb.org/t/p/w1280";
+const SEARCHPATH = "https://api.themoviedb.org/3/search/movie?&api_key=c5a20c861acf7bb8d9e987dcc7f1b558&query=";
+const searchTitle = document.getElementById("select-text");
+const searchButton = document.getElementById("button-search");
+const search = document.getElementById("search");
+const main = document.getElementById("movies-container");
+
+async function getMovies(url) {
+ clearMovieDetails();
+ const numberOfMovies = calculateMoviesToDisplay();
+ const pagesToFetch = numberOfMovies <= 20 ? 1 : 2;
+ let allMovies = [];
+ for (let page = 1; page <= pagesToFetch; page++) {
+ const response = await fetch(`${url}&page=${page}`);
+ const data = await response.json();
+ allMovies = allMovies.concat(data.results);
+ }
+ allMovies.sort((a, b) => b.vote_average - a.vote_average);
+ if (allMovies.length > 0) {
+ showMovies(allMovies.slice(0, numberOfMovies), main);
+ }
+ else {
+ main.innerHTML = ` No movie with the specified search term found. Please try again.
`;
+ }
+}
+
+function clearMovieDetails() {
+ const movieDetailsContainer = document.getElementById('movie-details-container');
+ if (movieDetailsContainer) {
+ movieDetailsContainer.innerHTML = '';
+ }
+}
+
+form.addEventListener('submit', (e) => {
+ e.preventDefault();
+ const searchTerm = search.value.trim();
+ if (searchTerm) {
+ getMovies(SEARCHPATH + searchTerm);
+ searchTitle.innerHTML = 'Search Results for: ' + searchTerm;
+ search.value = '';
+ }
+ else {
+ searchTitle.innerHTML = 'Please enter a search term.';
+ }
+ document.getElementById('clear-search-btn').style.display = 'block';
+});
+
+searchButton.addEventListener('click', (e) => {
+ e.preventDefault();
+ const searchTerm = search.value;
+ if (searchTerm) {
+ getMovies(SEARCHPATH + searchTerm);
+ searchTitle.innerHTML = 'Search Results for: ' + searchTerm;
+ search.value = '';
+ }
+ else {
+ searchTitle.innerHTML = 'Please enter a search term.';
+ }
+ document.getElementById('clear-search-btn').style.display = 'block';
+});
+
+function updateMovies() {
+ let startYear = document.getElementById('start-year').value;
+ let endYear = document.getElementById('end-year').value;
+ let currentYear = new Date().getFullYear();
+ if (startYear && endYear && startYear <= endYear && endYear <= currentYear) {
+ fetchMoviesByTimePeriod(startYear, endYear);
+ }
+ else {
+ alert('Please ensure the start year is before the end year, and both are not later than the current year.');
+ }
+}
+
+function showMovies(movies, mainElement) {
+ mainElement.innerHTML = '';
+ movies.forEach(movie => {
+ const movieEl = document.createElement('div');
+ movieEl.classList.add('movie');
+ const movieImage = movie.poster_path
+ ? `
`
+ : `
Image Not Available
`;
+ const voteAvg = movie.vote_average.toFixed(1);
+ const ratingClass = getClassByRate(movie.vote_average);
+ movieEl.innerHTML = `
+ ${movieImage}
+
+
${movie.title}
+ ${voteAvg}
+
+
+
Movie Intro:
+ ${movie.overview}
+ `;
+ movieEl.addEventListener('click', () => {
+ localStorage.setItem('selectedMovieId', movie.id);
+ window.location.href = 'movie-details.html';
+ });
+ movieEl.style.cursor = 'pointer';
+ mainElement.appendChild(movieEl);
+ });
+}
+
+document.getElementById('clear-search-btn').addEventListener('click', () => {
+ location.reload();
+});
+
+async function fetchMoviesByTimePeriod(startYear, endYear) {
+ const url = `https://api.themoviedb.org/3/discover/movie?api_key=c5a20c861acf7bb8d9e987dcc7f1b558&primary_release_date.gte=${startYear}-01-01&primary_release_date.lte=${endYear}-12-31`;
+ const response = await fetch(url);
+ const data = await response.json();
+ const numberOfMovies = calculateMoviesToDisplay();
+ const moviesToShow = data.results.slice(0, numberOfMovies);
+ showMovies(moviesToShow, document.getElementById('movies-container'));
+}
+
+document.getElementById('load-movies').addEventListener('click', () => {
+ const startYear = document.getElementById('start-year').value;
+ const endYear = document.getElementById('end-year').value;
+ fetchMoviesByTimePeriod(startYear, endYear);
+});
+
+function calculateMoviesToDisplay() {
+ const screenWidth = window.innerWidth;
+ if (screenWidth <= 689.9) return 10; // 1 movie per row
+ if (screenWidth <= 1021.24) return 20; // 2 movies per row
+ if (screenWidth <= 1353.74) return 21; // 3 movies per row
+ if (screenWidth <= 1684.9) return 20; // 4 movies per row
+ if (screenWidth <= 2017.49) return 20; // 5 movies per row
+ if (screenWidth <= 2349.99) return 18; // 6 movies per row
+ if (screenWidth <= 2681.99) return 21; // 7 movies per row
+ if (screenWidth <= 3014.49) return 24; // 8 movies per row
+ if (screenWidth <= 3345.99) return 27; // 9 movies per row
+ if (screenWidth <= 3677.99) return 20; // 10 movies per row
+ if (screenWidth <= 4009.99) return 22; // 11 movies per row
+ if (screenWidth <= 4340.99) return 24; // 12 movies per row
+ if (screenWidth <= 4673.49) return 26; // 13 movies per row
+ if (screenWidth <= 5005.99) return 28; // 14 movies per row
+ if (screenWidth <= 5337.99) return 30; // 15 movies per row
+ if (screenWidth <= 5669.99) return 32; // 16 movies per row
+ if (screenWidth <= 6001.99) return 34; // 17 movies per row
+ if (screenWidth <= 6333.99) return 36; // 18 movies per row
+ if (screenWidth <= 6665.99) return 38; // 19 movies per row
+ if (screenWidth <= 6997.99) return 40; // 20 movies per row
+ if (screenWidth <= 7329.99) return 42; // 21 movies per row
+ if (screenWidth <= 7661.99) return 44; // 22 movies per row
+ if (screenWidth <= 7993.99) return 46; // 23 movies per row
+ if (screenWidth <= 8325.99) return 48; // 24 movies per row
+ return 20;
+}
+
+function getClassByRate(vote) {
+ if (vote >= 8) {
+ return 'green';
+ }
+ else if (vote >= 5) {
+ return 'orange';
+ }
+ else {
+ return 'red';
+ }
+}
+
+async function showMovieOfTheDay(){
+ const year = new Date().getFullYear();
+ const url = `https://api.themoviedb.org/3/discover/movie?api_key=c5a20c861acf7bb8d9e987dcc7f1b558&sort_by=vote_average.desc&vote_count.gte=100&primary_release_year=${year}&vote_average.gte=7`;
+ try {
+ const response = await fetch(url);
+ const data = await response.json();
+ const movies = data.results;
+ const randomMovie = movies[Math.floor(Math.random() * movies.length)];
+ localStorage.setItem('selectedMovieId', randomMovie.id);
+ window.location.href = 'movie-details.html';
+ }
+ catch (error) {
+ console.error('Error fetching movie:', error);
+ alert('Failed to fetch the movie of the day. Please try again later.');
+ }
+}
diff --git a/MovieVerse-Mobile/www/style.css b/MovieVerse-Mobile/www/style.css
index 4990350c..58c0ae17 100644
--- a/MovieVerse-Mobile/www/style.css
+++ b/MovieVerse-Mobile/www/style.css
@@ -313,6 +313,15 @@ h2:hover {
transition: 0.1s linear;
}
+header {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 1.5rem;
+}
+
+
#movie-of-the-day-btn {
position: fixed;
bottom: 140px;
@@ -923,3 +932,149 @@ p {
.director-link:hover {
color: #f509d9;
}
+
+/* Movie Card Style */
+.movie-card {
+ background-color: #373b69;
+ border-radius: 3px;
+ box-shadow: 0 4px 5px rgba(0,0,0,0.2);
+ margin: 1rem;
+ color: white;
+ position: relative;
+ overflow: hidden;
+ width: 300px;
+}
+
+.movie-card img {
+ width: 100%;
+}
+
+.movie-info {
+ color: #eee;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 0.5rem 1rem 1rem;
+ letter-spacing: 0.5px;
+}
+
+.movie-info h3 {
+ margin: 0;
+}
+
+#load-movies {
+ padding: 10px 20px;
+ background-color: #7378c5;
+ color: white;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+ font-size: 1rem;
+}
+
+#load-movies:hover {
+ background-color: #ff8623;
+}
+
+.movie-info span {
+ background-color: #22254b;
+ border-radius: 3px;
+ font-weight: bold;
+ padding: 0.25rem 0.5rem;
+}
+
+.timeline-container {
+ text-align: center;
+}
+
+#load-movies {
+ cursor: pointer;
+ font: inherit;
+}
+
+#movie-timeline-btn {
+ position: fixed;
+ bottom: 180px;
+ right: 30px;
+ background-color: #7378c5;
+ font: inherit;
+ color: black;
+ border-radius: 8px;
+ border: none;
+ cursor: pointer;
+}
+
+#movie-timeline-btn:hover {
+ background-color: #ff8623;
+ transition: 0.3s ease-in;
+}
+
+#movies-container {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ align-items: stretch;
+ margin: 0 auto;
+ padding: 20px;
+}
+
+.center-container {
+ text-align: center;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ display: flex;
+}
+
+#load-movies {
+ cursor: pointer;
+ font: inherit;
+}
+
+#select-text {
+ margin-top: 60px;
+ color: #ff8623;
+}
+
+#select-text:hover {
+ color: #f509d9;
+}
+
+#search-title {
+ margin-top: 50px;
+}
+
+#clear-search-btn {
+ background-color: #7378c5;
+ color: black;
+ border: none;
+ padding: 5px 10px;
+ border-radius: 5px;
+ cursor: pointer;
+ margin-left: 10px;
+ font: inherit;
+ margin-right: 20px;
+}
+
+#clear-search-btn:hover {
+ background-color: #ff8623;
+}
+
+@media screen and (-webkit-min-device-pixel-ratio: 0) {
+ body {
+ background-size: auto;
+ background-repeat: repeat;
+ }
+}
+
+.year-input-container {
+ margin: 20px;
+}
+
+.year-input {
+ width: 150px;
+ padding: 10px;
+ margin: 5px;
+ border-radius: 5px;
+ border: 1px solid #ddd;
+}
diff --git a/MovieVerse-Mobile/www/trivia.html b/MovieVerse-Mobile/www/trivia.html
index fe315b30..ad68bf46 100644
--- a/MovieVerse-Mobile/www/trivia.html
+++ b/MovieVerse-Mobile/www/trivia.html
@@ -6,6 +6,7 @@
+
diff --git a/about.html b/about.html
index 012eec2c..2e34941c 100644
--- a/about.html
+++ b/about.html
@@ -16,7 +16,7 @@
The MovieVerse - About Us
Movie Timeline
Movie of the Day
MovieVerse Chatbot
-
Trivia Game
+
MovieVerse Trivia
diff --git a/actor-details.html b/actor-details.html
index 5a62cd68..31e09352 100644
--- a/actor-details.html
+++ b/actor-details.html
@@ -4,6 +4,7 @@
Actor Details
+
@@ -33,6 +34,7 @@
+ Clear Search Results
@@ -62,7 +64,7 @@
MovieVerse Chatbot
- Trivia Game
+ MovieVerse Trivia