Skip to content

Commit

Permalink
set up movie list and moive detail view
Browse files Browse the repository at this point in the history
  • Loading branch information
sageseid committed Jun 8, 2022
1 parent c9e1689 commit 0549308
Show file tree
Hide file tree
Showing 27 changed files with 1,008 additions and 65 deletions.
78 changes: 70 additions & 8 deletions Flicks.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildLocationStyle</key>
<string>UseAppPreferences</string>
<key>CustomBuildLocationType</key>
<string>RelativeToDerivedData</string>
<key>DerivedDataLocationStyle</key>
<string>Default</string>
<key>IssueFilterStyle</key>
<string>ShowActiveSchemeOnly</string>
<key>LiveSourceIssuesEnabled</key>
<true/>
<key>ShowSharedSchemesAutomaticallyEnabled</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "Loading_Default_Picture copy.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 0 additions & 21 deletions Flicks/ContentView.swift

This file was deleted.

5 changes: 4 additions & 1 deletion Flicks/FlicksApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import SwiftUI

@main
struct FlicksApp: App {
let persistenceController = PersistenceController.shared

var body: some Scene {
WindowGroup {
ContentView()
MovieListView()
.environment(\.managedObjectContext, persistenceController.viewContext)
}
}
}
60 changes: 60 additions & 0 deletions Flicks/core/movieDetails/MovieDetailsView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// MovieDetailsView.swift
// Flicks
//
// Created by Noel Obaseki on 06/06/2022.
//

import SwiftUI

struct MovieDetailsView: View {
@StateObject var viewModel: MovieDetailsViewModel
@StateObject var imageHandlerViewModel = ImageProvider()

var body: some View {
VStack(spacing: 0) {
if viewModel.showNoData {
Text("Unable to load Movie details")
} else if viewModel.isLoading {
ProgressView()
.frame(width: 50, height: 50)
} else if let movieDetails = viewModel.movieDetails {
if viewModel.isOffline {
OfflineBarView()
}

ScrollView {

Image(uiImage: imageHandlerViewModel.image).resizable()
.renderingMode(.original)
.aspectRatio(contentMode:.fill)
.frame(width:60,height:300)
.cornerRadius(10)
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(Color.black, lineWidth: 1))
.onAppear {
imageHandlerViewModel.loadImage(url:URL(string: "\(Constants.Image.baseUrl)\(movieDetails.posterPath!)" )! )
}


VStack(alignment: .leading, spacing: 10) {
Text(movieDetails.title ?? "Missing Title")
Text("Overview:").bold()
Text(movieDetails.overview ?? "No Overview")
.fixedSize(horizontal: false, vertical: true)
}
.padding(.horizontal, 8)
Spacer()
}
}
}
.navigationBarTitle("Movie Details", displayMode: .inline)

}
}

//struct MovieDetailsView_Previews: PreviewProvider {
// static var previews: some View {
// MovieDetailsView()
// }
//}
26 changes: 26 additions & 0 deletions Flicks/core/movieDetails/MovieDetailsViewDestination.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//
// MovieDetailsViewDestination.swift
// Flicks
//
// Created by Noel Obaseki on 07/06/2022.
//

import SwiftUI

struct MovieDetailsViewDestination: View {
let movieId: String
let viewModel: MovieListViewModel

var body: some View {
MovieDetailsView(viewModel: MovieDetailsViewModel(movieId: movieId))
.onDisappear(perform: {
viewModel.loadMoviesIfNeeded()
})
}
}

//struct MovieDetailsViewDestination_Previews: PreviewProvider {
// static var previews: some View {
// MovieDetailsViewDestination()
// }
//}
109 changes: 109 additions & 0 deletions Flicks/core/movieDetails/MovieDetailsViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//
// MovieDetailViewModel.swift
// Flicks
//
// Created by Noel Obaseki on 06/06/2022.
//

import Foundation
import Combine


class MovieDetailsViewModel: ObservableObject {

private let movieId: String

@Published var isLoading: Bool = false
@Published var movieDetails: MovieDetails? = nil
@Published var dataType: DataType = .noData

@Published var isOffline = false
@Published var showNoData = false
@Published var showDetails = false

private lazy var showOfflineView: AnyPublisher<Bool, Never> = {
Publishers
.CombineLatest3(self.$dataType, self.$isLoading, self.$movieDetails)
.map { element in
if element.0 == .cached, !element.1, element.2 != nil {
return true
} else {
return false
}
}
.eraseToAnyPublisher()
}()

private lazy var showNoDataLabel: AnyPublisher<Bool, Never> = {
Publishers
.CombineLatest(self.$movieDetails, self.$isLoading)
.map { element in
if element.0 == nil, !element.1 {
return true
} else {
return false
}
}
.eraseToAnyPublisher()
}()

private lazy var showDetailsView: AnyPublisher<Bool, Never> = {
Publishers
.CombineLatest(self.$movieDetails, self.$isLoading)
.map { element in
if element.0 != nil, !element.1 {
return false
} else {
return true
}
}
.eraseToAnyPublisher()
}()

@Published var error: Error? = nil

let movieDetailsStore: MovieDetailsProtocol

private var cancellableSet: Set<AnyCancellable> = []

init(movieId: String, movieDetailsStore: MovieDetailsProtocol = MovieDetailsService()) {
self.movieId = movieId
self.movieDetailsStore = movieDetailsStore

showOfflineView.assign(to: &self.$isOffline)
showNoDataLabel.assign(to: &self.$showNoData)
showDetailsView.assign(to: &self.$showDetails)

// NotificationCenter.default.publisher(for: .reachabilityChanged)
// .sink(receiveValue: { [weak self] (notification) in
// guard let self = self, let reachability = notification.object as? Reachability,
// reachability.connection != .unavailable, self.dataType != .live else { return }
// self.getMovieDetails()
// })
// .store(in: &cancellableSet)

bindStore()
getMovieDetails()
}

func bindStore() {
movieDetailsStore
.movieDetailsSubject
.sink { [weak self] (completion) in
switch completion {
case .finished: break
case .failure(let error):
self?.error = error
}
} receiveValue: { [weak self] (storeState) in
self?.isLoading = false
self?.dataType = storeState.dataType
self?.movieDetails = storeState.movieDetails
}.store(in: &cancellableSet)
}

func getMovieDetails() {
self.isLoading = true
movieDetailsStore.getMovieDetails(id: self.movieId)
}
}
60 changes: 60 additions & 0 deletions Flicks/core/movies/MovieListView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// ContentView.swift
// Flicks
//
// Created by Noel Obaseki on 21/04/2022.
//

import SwiftUI
import CoreData

struct MovieListView: View {
@Environment(\.managedObjectContext) private var viewContext

@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Movie.id, ascending: true)],
animation: .default)
private var movies: FetchedResults<Movie>

@StateObject private var viewModel = MovieListViewModel()

var body: some View {
NavigationView {
VStack(spacing: 0) {
if viewModel.showNoData {
Text("Unable to load Movies list")
} else if viewModel.isLoading {
ProgressView()
.frame(width: 50, height: 50)
} else {
if viewModel.isOffline {
OfflineBarView()
}
ScrollView {
LazyVStack(spacing: 15) {
ForEach(movies) { movie in
NavigationLink(destination: MovieDetailsViewDestination(movieId: movie.id!, viewModel: viewModel)) {
MovieView(movie: movie, height: 200)
.background(Color.white)
.cornerRadius(15)
.shadow(radius: 3)
}
}.buttonStyle(PlainButtonStyle())
}.padding()
}
}
}
.navigationBarTitle("Movies", displayMode: .inline)
}
.background(Color(UIColor.systemGray6))
}
}




//struct ContentView_Previews: PreviewProvider {
// static var previews: some View {
// MovieListView()
// }
//}
Loading

0 comments on commit 0549308

Please sign in to comment.