Move towards having views be initialized with a view model.

- As opposed to being responsible for initializing their own.
This commit is contained in:
CypherPoet 2020-01-06 13:28:43 -06:00
parent 1a183b2f7b
commit ddb4f20990
6 changed files with 95 additions and 54 deletions

View File

@ -13,12 +13,7 @@ struct EditLocationView: View {
@Environment(\.presentationMode) var presentationMode
@EnvironmentObject var store: AppStore
@ObservedObject private(set) var viewModel: EditLocationViewModel
init(location: Location) {
self.viewModel = EditLocationViewModel(location: location)
}
@ObservedObject var viewModel: EditLocationViewModel
}
@ -28,12 +23,47 @@ extension EditLocationView {
var body: some View {
NavigationView {
Form {
Section {
TextField("Location Name", text: Binding($viewModel.location.title, "Untitled Location"))
// TextField("Description", text: Binding($viewModel.location.longDescription, ""))
TextField("Description", text: Binding($viewModel.location.longDescription, replacingNilWith: ""))
Section(header: Text("Details").font(.headline)) {
TextField(
"Location Name",
text: Binding($viewModel.location.title, "Untitled Location")
)
TextField(
"Description",
text: Binding($viewModel.location.longDescription, replacingNilWith: "")
)
}
Section(header: Text("Add A Photo").font(.headline)) {
Button(action: {
}) {
Group {
// if viewModel.location.userPhoto != nil {
if false {
} else {
HStack {
Spacer()
VStack {
Image(systemName: "camera")
.resizable()
.scaledToFit()
.frame(width: 120)
Text("No Photo Selected")
.font(.title)
}
Spacer()
}
}
}
.frame(height: 200)
}
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
}
.padding(.bottom)
Section(header: Text("Nearby Locations...").font(.headline)) {
@ -52,8 +82,6 @@ extension EditLocationView {
.navigationBarItems(trailing: saveButton)
}
.onAppear {
self.viewModel.store = self.store
self.store.send(.wikiPages(.fetchStateSet(.fetching)))
self.store.send(WikiPagesSideEffect.fetchPages(near: self.viewModel.location))
}
@ -87,7 +115,10 @@ struct EditLocationView_Previews: PreviewProvider {
static var previews: some View {
EditLocationView(
location: SampleData.Locations.santorini
viewModel: EditLocationViewModel(
location: SampleData.Locations.santorini,
wikiPagesState: SampleData.SampleAppStore.default.state.wikiPagesState
)
)
.environment(\.managedObjectContext, CurrentApp.coreDataManager.mainContext)
.environmentObject(SampleData.SampleAppStore.default)

View File

@ -14,23 +14,24 @@ import Combine
final class EditLocationViewModel: ObservableObject {
private var subscriptions = Set<AnyCancellable>()
var store: AppStore! {
didSet {
guard store != nil else { return }
self.setupSubscribers()
}
}
@ObservedObject var location: Location
private let wikiPagesState: WikiPagesState
init(location: Location) {
self.location = location
}
// MARK: - Published Outputs
@Published var wikiPagesFetchState: WikiPagesState.FetchState = .inactive
// MARK: - Init
init(
location: Location,
wikiPagesState: WikiPagesState
) {
self.location = location
self.wikiPagesState = wikiPagesState
setupSubscribers()
}
}
@ -38,8 +39,7 @@ final class EditLocationViewModel: ObservableObject {
extension EditLocationViewModel {
private var wikiPagesFetchStatePublisher: AnyPublisher<WikiPagesState.FetchState, Never> {
store.$state
.map(\.wikiPagesState.currentFetchState)
CurrentValueSubject(wikiPagesState.currentFetchState)
.eraseToAnyPublisher()
}
}

View File

@ -13,17 +13,12 @@ import MapKit
struct LocationCollectionView: View {
@EnvironmentObject var store: AppStore
@ObservedObject private(set) var viewModel: LocationCollectionViewModel
@ObservedObject var viewModel: LocationCollectionViewModel
@State private var centerCoordinate = CLLocationCoordinate2D()
@State var selectedLocation: Location? = nil
@State private var isShowingEditView = false
@State private var isShowingSelectedLocationAlert = false
init(collection: LocationCollection) {
self.viewModel = LocationCollectionViewModel(collection: collection)
}
}
@ -49,8 +44,13 @@ extension LocationCollectionView {
}
) {
if self.selectedLocation != nil {
EditLocationView(location: self.selectedLocation!)
.environmentObject(self.store)
EditLocationView(
viewModel: EditLocationViewModel(
location: self.selectedLocation!,
wikiPagesState: self.store.state.wikiPagesState
)
)
.environmentObject(self.store)
} else {
Text("No Location found for editing")
}
@ -59,14 +59,14 @@ extension LocationCollectionView {
Alert(
title: Text(selectedLocation?.title ?? "Undisclosed Location"),
message: Text(selectedLocation?.longDescription ?? "No description has been provided yet."),
primaryButton: .default(Text("Edit"), action: {
self.isShowingEditView = true
}),
primaryButton: .default(
Text("Edit"),
action: { self.isShowingEditView = true }
),
secondaryButton: .cancel(Text("OK"))
)
}
}
}
@ -152,7 +152,9 @@ private extension LocationCollectionView {
struct LocationCollectionView_Previews: PreviewProvider {
static var previews: some View {
LocationCollectionView(collection: SampleData.LocationCollections.default)
.environmentObject(SampleData.SampleAppStore.default)
LocationCollectionView(
viewModel: LocationCollectionViewModel(collection: SampleData.LocationCollections.default)
)
.environmentObject(SampleData.SampleAppStore.default)
}
}

View File

@ -20,13 +20,6 @@ final class LocationCollectionViewModel: NSObject, ObservableObject {
// MARK: - Published Outputs
@Published var locations: [Location] = []
@Published var isShowingEditView: Bool = false
@Published var isShowingSelectedLocationAlert: Bool = false {
didSet {
print("isShowingSelectedLocationAlert - didSet: \(isShowingSelectedLocationAlert)")
}
}
// MARK: - Init
@ -34,9 +27,6 @@ final class LocationCollectionViewModel: NSObject, ObservableObject {
self.collection = collection
super.init()
// self.fetchedResultsController.delegate = self
// fetchLocations()
}

View File

@ -22,7 +22,7 @@ extension LocationCollectionsContainerView {
Group {
if viewModel.isAuthenticated {
LocationCollectionsListView(
buildDestination: LocationCollectionView.init(collection:)
buildDestination: LocationCollectionsContainerViewModel.destination(for:)
)
} else {
authenticationNotice
@ -83,6 +83,16 @@ extension LocationCollectionsContainerView {
}
private extension LocationCollectionsContainerView {
func destination(for locationCollection: LocationCollection) -> LocationCollectionView {
let viewModel = LocationCollectionViewModel(collection: locationCollection)
return LocationCollectionView(viewModel: viewModel)
}
}
// MARK: - Preview
struct LocationCollectionsContainerView_Previews: PreviewProvider {

View File

@ -64,9 +64,17 @@ extension LocationCollectionsContainerViewModel {
)
.store(in: &subscriptions)
}
static func destination(for locationCollection: LocationCollection) -> LocationCollectionView {
let viewModel = LocationCollectionViewModel(collection: locationCollection)
return .init(viewModel: viewModel)
}
}
// MARK: - Computed
// MARK: - Computeds
extension LocationCollectionsContainerViewModel {
var authenticationErrorAlertTitle: String { "Authentication Failed" }