From b92214eb057fb0cad1fb8f02ad1e1660abe5a19c Mon Sep 17 00:00:00 2001 From: Iván Ávalos Date: Tue, 8 Feb 2022 21:48:00 -0600 Subject: - Fixed DetailsView. - Refactored details sheet into UnitsView. - A lot of logic moved into view models. - Implemented unit details in UnitMapView. --- iosApp/iosApp.xcodeproj/project.pbxproj | 4 +++ iosApp/iosApp/Details/DetailsView.swift | 30 +++++++++-------- iosApp/iosApp/Devices/DevicesView.swift | 39 +++++++--------------- iosApp/iosApp/Devices/DevicesViewModel.swift | 48 ++++++++++++++++++++++++++++ iosApp/iosApp/Map/MapViewController.swift | 18 +++-------- iosApp/iosApp/Map/UnitMapView.swift | 4 +-- iosApp/iosApp/Units/UnitsView.swift | 7 ++++ iosApp/iosApp/Units/UnitsViewModel.swift | 10 ++++++ 8 files changed, 104 insertions(+), 56 deletions(-) create mode 100644 iosApp/iosApp/Devices/DevicesViewModel.swift diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index 7dea34f..f18e5b2 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; }; 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; }; 7555FF83242A565900829871 /* RootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* RootView.swift */; }; + E312E74F27B366060018C5DE /* DevicesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E312E74E27B366060018C5DE /* DevicesViewModel.swift */; }; E3385A4F27B0D8A10025311C /* UnitCommandsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3385A4E27B0D8A10025311C /* UnitCommandsViewModel.swift */; }; E33A236027A4FD2C00DD647F /* UnitMapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A235F27A4FD2C00DD647F /* UnitMapView.swift */; }; E33A236527A530F300DD647F /* SmallLabelStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E33A236427A530F300DD647F /* SmallLabelStyle.swift */; }; @@ -61,6 +62,7 @@ 7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7555FF82242A565900829871 /* RootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootView.swift; sourceTree = ""; }; 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E312E74E27B366060018C5DE /* DevicesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesViewModel.swift; sourceTree = ""; }; E3385A4E27B0D8A10025311C /* UnitCommandsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitCommandsViewModel.swift; sourceTree = ""; }; E33A235F27A4FD2C00DD647F /* UnitMapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitMapView.swift; sourceTree = ""; }; E33A236427A530F300DD647F /* SmallLabelStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallLabelStyle.swift; sourceTree = ""; }; @@ -214,6 +216,7 @@ children = ( E39ABC4527A4EBD500965D05 /* DevicesView.swift */, E39ABC4727A4EDEC00965D05 /* DeviceRow.swift */, + E312E74E27B366060018C5DE /* DevicesViewModel.swift */, ); path = Devices; sourceTree = ""; @@ -350,6 +353,7 @@ E38F241727A242C70069FC45 /* Resolver.swift in Sources */, E33A236027A4FD2C00DD647F /* UnitMapView.swift in Sources */, E396282427AFBD3D005D070E /* UnitInformationView.swift in Sources */, + E312E74F27B366060018C5DE /* DevicesViewModel.swift in Sources */, E33A236727A64E4500DD647F /* MarkerTransformations.swift in Sources */, E38F241527A242870069FC45 /* Inject.swift in Sources */, E39ABC4827A4EDEC00965D05 /* DeviceRow.swift in Sources */, diff --git a/iosApp/iosApp/Details/DetailsView.swift b/iosApp/iosApp/Details/DetailsView.swift index 8e2a6b5..25c8611 100644 --- a/iosApp/iosApp/Details/DetailsView.swift +++ b/iosApp/iosApp/Details/DetailsView.swift @@ -23,29 +23,33 @@ struct DetailsView: View { @Binding var isPresented: Bool @State var action: DeviceRow.Action - var id: Int32 + var id: Int32? - init(isPresented: Binding, action: DeviceRow.Action, forId id: Int32) { + init(isPresented: Binding, action: DeviceRow.Action, forId id: Int32?) { self._isPresented = isPresented self.action = action self.id = id - detailsViewModel.fetchUnit(id: id) + if let id = id { + self.detailsViewModel.fetchUnit(id: id) + } } var body: some View { NavigationView { VStack { - if let unit = detailsViewModel.unit { - switch action { - case .details: - UnitInformationView(unit: unit) - case .reports: - UnitReportsView(unit: unit) - case .commands: - UnitCommandsView(unit: unit) + if id != nil { + if let unit = detailsViewModel.unit { + switch action { + case .details: + UnitInformationView(unit: unit) + case .reports: + UnitReportsView(unit: unit) + case .commands: + UnitCommandsView(unit: unit) + } + } else { + LoadingView() } - } else { - LoadingView() } } .navigationBarTitleView( diff --git a/iosApp/iosApp/Devices/DevicesView.swift b/iosApp/iosApp/Devices/DevicesView.swift index d3a361e..06f1df1 100644 --- a/iosApp/iosApp/Devices/DevicesView.swift +++ b/iosApp/iosApp/Devices/DevicesView.swift @@ -18,35 +18,20 @@ import SwiftUI struct DevicesView: View { - @StateObject var unitsViewModel: UnitsViewModel - @State var shouldShowView = false - @State var action: DeviceRow.Action = .details - @State var id: Int32? + @ObservedObject var devicesViewModel: DevicesViewModel + + init (unitsViewModel: UnitsViewModel) { + self._devicesViewModel = ObservedObject( + wrappedValue: DevicesViewModel(unitsViewModel: unitsViewModel)) + } var body: some View { - VStack { - List(unitsViewModel.units, id: \.device.id) { unit in - DeviceRow(unit: unit, callback: { action in - self.action = action - id = unit.device.id - shouldShowView = true - }) - .onTapGesture { - unitsViewModel.searchQuery = "" - unitsViewModel.isEditing = false - unitsViewModel.unitsDisplayMode = .map - unitsViewModel.selectedUnit = unit - UIApplication.shared.endEditing() - } - } - } - .sheet(isPresented: $shouldShowView) { - print("Dismissed") - } content: { - if let id = id { - DetailsView(isPresented: $shouldShowView, - action: action, - forId: id) + List(devicesViewModel.units, id: \.device.id) { unit in + DeviceRow(unit: unit, callback: { action in + self.devicesViewModel.show(action: action, for: unit) + }).onTapGesture { + self.devicesViewModel.select(unit: unit) + UIApplication.shared.endEditing() } } } diff --git a/iosApp/iosApp/Devices/DevicesViewModel.swift b/iosApp/iosApp/Devices/DevicesViewModel.swift new file mode 100644 index 0000000..76cf9a2 --- /dev/null +++ b/iosApp/iosApp/Devices/DevicesViewModel.swift @@ -0,0 +1,48 @@ +/** + * TrackerMap + * Copyright (C) 2021-2022 Iván Ávalos , Henoch Ojeda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +import Foundation +import shared + +class DevicesViewModel: ObservableObject { + var unitsViewModel: UnitsViewModel + var id: Int32? = nil + var units: [UnitInformation] { + get { + return unitsViewModel.units + } + } + + @Published var shouldShowView = false + @Published var action: DeviceRow.Action = .details + + init(unitsViewModel: UnitsViewModel) { + self.unitsViewModel = unitsViewModel + } + + func select(unit: UnitInformation) { + unitsViewModel.searchQuery = "" + unitsViewModel.isEditing = false + unitsViewModel.unitsDisplayMode = .map + unitsViewModel.selectedUnit = unit + + } + + func show(action: DeviceRow.Action, for unit: UnitInformation) { + unitsViewModel.show(action: action, for: unit) + } +} diff --git a/iosApp/iosApp/Map/MapViewController.swift b/iosApp/iosApp/Map/MapViewController.swift index 32c21cf..bc793e2 100644 --- a/iosApp/iosApp/Map/MapViewController.swift +++ b/iosApp/iosApp/Map/MapViewController.swift @@ -63,7 +63,7 @@ class MapViewController: UIViewController { mapView.setLoader(loader) } - DispatchQueue.main.async { + mapView.runOnInit { let point = MaplyCoordinateMakeWithDegrees(-100.36, 23.191) self.mapView.setPosition(point, height: 0.4) } @@ -135,23 +135,13 @@ extension MapViewController: MaplyViewControllerDelegate { } class OurMaplyViewController: MaplyViewController { - enum Action { - case zoomIn - case zoomOut - } - private var loader: MaplyQuadImageLoader? = nil private var objects = [MaplyComponentObject]() private var geofenceObjects = [MaplyComponentObject]() - func action(_ action: Action) { - DispatchQueue.main.async { - switch action { - case .zoomIn: - self.zoomIn() - case .zoomOut: - self.zoomOut() - } + func runOnInit(callback: @escaping () -> ()) { + addPostInitBlock { + callback() } } diff --git a/iosApp/iosApp/Map/UnitMapView.swift b/iosApp/iosApp/Map/UnitMapView.swift index d2ad8a8..533ac13 100644 --- a/iosApp/iosApp/Map/UnitMapView.swift +++ b/iosApp/iosApp/Map/UnitMapView.swift @@ -30,10 +30,10 @@ struct UnitMapView: View { if let unit = unitsViewModel.selectedUnit { VStack { DeviceRow(unit: unit, callback: { action in - print("Action is \(action)") + unitsViewModel.show(action: action, for: unit) }, isCell: false) .padding() - .background(.systemBackground) + .background(.secondarySystemBackground) } .frame(maxWidth: .infinity, maxHeight: .infinity, diff --git a/iosApp/iosApp/Units/UnitsView.swift b/iosApp/iosApp/Units/UnitsView.swift index aedb165..bfd4e06 100644 --- a/iosApp/iosApp/Units/UnitsView.swift +++ b/iosApp/iosApp/Units/UnitsView.swift @@ -74,6 +74,13 @@ struct UnitsView: View { } } .navigationViewStyle(StackNavigationViewStyle()) + .sheet(isPresented: $unitsViewModel.showDetails) { + print("Dismissed") + } content: { + DetailsView(isPresented: $unitsViewModel.showDetails, + action: unitsViewModel.showAction, + forId: unitsViewModel.tappedId) + } } private func getNavigationTitle(_ unitDisplayMode: UnitsViewModel.UnitsDisplayMode) -> LocalizedStringKey { diff --git a/iosApp/iosApp/Units/UnitsViewModel.swift b/iosApp/iosApp/Units/UnitsViewModel.swift index b657675..f561504 100644 --- a/iosApp/iosApp/Units/UnitsViewModel.swift +++ b/iosApp/iosApp/Units/UnitsViewModel.swift @@ -41,6 +41,8 @@ class UnitsViewModel: ObservableObject { } } + var tappedId: Int32? = nil + @Published var searchQuery = "" { didSet { unitsDisplayMode = .list @@ -48,6 +50,8 @@ class UnitsViewModel: ObservableObject { } } @Published var isEditing = false + @Published var showDetails = false + @Published var showAction = DeviceRow.Action.details @Published var unitsDisplayMode: UnitsDisplayMode = .list @Published var units: [UnitInformation] = [] { didSet { @@ -121,4 +125,10 @@ class UnitsViewModel: ObservableObject { func search(query: String) { unitsController.search(query: query) } + + func show(action: DeviceRow.Action, for unit: UnitInformation) { + showAction = action + tappedId = unit.device.id + showDetails = true + } } -- cgit v1.2.3