/** * 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 WhirlyGlobe import shared class UnitsViewModel: ObservableObject { @Inject var unitsController: UnitsController @Inject var geofenceController: GeofencesController let mainScope = MainScope.companion.createMainScope() enum UnitsDisplayMode { case map case list } var detailsUnit: UnitInformation? = nil var detailsAction = DeviceRow.Action.details @Published var searchQuery = "" { didSet { unitsDisplayMode = .list search(query: searchQuery) } } @Published var isEditing = false @Published var showDetails = false @Published var showUserInfo = false @Published var unitsDisplayMode: UnitsDisplayMode = .map @Published var units: [UnitInformation] = [] { didSet { markers = units.compactMap(Marker.companion.fromUnit) } } @Published var markers: [Marker] = [] @Published var oldSelectedUnit: UnitInformation? = nil @Published var selectedUnit: UnitInformation? = nil { didSet { if selectedUnit?.device.id != oldSelectedUnit?.device.id { if let unit = selectedUnit { selectedMarker = Marker.companion.fromUnit(unit: unit) } else { selectedMarker = nil } } } } @Published var selectedMarker: Marker? = nil @Published var mapLayerType: MapLayer = .companion.defaultLayer @Published var geofences: [Int: Geofence] = [:] { didSet { flatGeofences = Array(geofences.values) } } @Published var flatGeofences: [Geofence] = [] init() { unitsController.fetchUnits(scope: mainScope) setupObservers() } deinit { MainScope.companion.cancelScope(scope: mainScope) } private func setupObservers() { let unitsCollector = Collector<[UnitInformation]>(callback: setUnits) unitsController.displayedUnitsFlow.collect(collector: unitsCollector) { unit, error in } let geofencesCollector = Collector<[Int: Geofence]>(callback: setGeofences) geofenceController.geofencesFlow.collect(collector: geofencesCollector) { unit, error in } } private func setUnits(units: [UnitInformation]) { print("Positions") self.units = units updateSelectedUnit() } private func setGeofences(geofences: [Int: Geofence]) { self.geofences = geofences } func selectUnit(unit: UnitInformation?, switchToMap: Bool = true) { print ("Selecting unit \(unit?.device.name ?? "")") oldSelectedUnit = selectedUnit selectedUnit = unit if unit != nil && switchToMap { setDisplayMode(UnitsDisplayMode.map) } } func selectUnitWith(position id: Int32?, switchToMap: Bool = true) { if id == nil { print("Deselecting unit") selectUnit(unit: nil, switchToMap: switchToMap) return } print("Selecting unit with position id: \(id!)") let unit = units.first { Int32(truncating: $0.position?.id ?? 0) == id! } selectUnit(unit: unit, switchToMap: switchToMap) } private func selectUnitWith(id: Int32?, switchToMap: Bool = true) { if id == nil { print("Deselecting unit") selectUnit(unit: nil, switchToMap: switchToMap) return } print("Selecting unit with device id: \(id!)") let unit = units.first { $0.device.id == id! } selectUnit(unit: unit, switchToMap: switchToMap) } private func updateSelectedUnit() { if let selected = selectedUnit { print("Updating selected unit with id: \(selected.device.id)") selectUnitWith(id: selected.device.id, switchToMap: false) } } func setDisplayMode(_ displayMode: UnitsDisplayMode) { unitsDisplayMode = displayMode } func toggleDisplayMode() { switch unitsDisplayMode { case .map: setDisplayMode(.list) case .list: setDisplayMode(.map) } } func search(query: String) { unitsController.search(query: query) } func show(action: DeviceRow.Action, for unit: UnitInformation) { if action != .close { detailsAction = action detailsUnit = unit showDetails = true } else { selectedUnit = nil } } }