Fix adding events. Remove old events screen.
This commit is contained in:
parent
deb3dae992
commit
57c222b937
@ -178,7 +178,6 @@
|
|||||||
7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6CA02512244400F237B2 /* MapExt.swift */; };
|
7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6CA02512244400F237B2 /* MapExt.swift */; };
|
||||||
7AE24C5F251F1B4E00758E39 /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE24C5E251F1B4E00758E39 /* Buttons.swift */; };
|
7AE24C5F251F1B4E00758E39 /* Buttons.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE24C5E251F1B4E00758E39 /* Buttons.swift */; };
|
||||||
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */; };
|
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */; };
|
||||||
7AE26A3524F31B0700625033 /* EventsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3424F31B0700625033 /* EventsController.swift */; };
|
|
||||||
7AEFC3BE2529D3CC00BADFB2 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFC3BD2529D3CC00BADFB2 /* ConfigurableCell.swift */; };
|
7AEFC3BE2529D3CC00BADFB2 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFC3BD2529D3CC00BADFB2 /* ConfigurableCell.swift */; };
|
||||||
7AF6D2042677C03B0086EA64 /* AutoCatCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; };
|
7AF6D2042677C03B0086EA64 /* AutoCatCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; };
|
||||||
7AF6D2052677C03B0086EA64 /* AutoCatCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
7AF6D2052677C03B0086EA64 /* AutoCatCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
@ -445,7 +444,6 @@
|
|||||||
7ADF6CA02512244400F237B2 /* MapExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapExt.swift; sourceTree = "<group>"; };
|
7ADF6CA02512244400F237B2 /* MapExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapExt.swift; sourceTree = "<group>"; };
|
||||||
7AE24C5E251F1B4E00758E39 /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
|
7AE24C5E251F1B4E00758E39 /* Buttons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Buttons.swift; sourceTree = "<group>"; };
|
||||||
7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerExt.swift; sourceTree = "<group>"; };
|
7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerExt.swift; sourceTree = "<group>"; };
|
||||||
7AE26A3424F31B0700625033 /* EventsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventsController.swift; sourceTree = "<group>"; };
|
|
||||||
7AE8424D26109F78002F6B31 /* Exportable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exportable.swift; sourceTree = "<group>"; };
|
7AE8424D26109F78002F6B31 /* Exportable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Exportable.swift; sourceTree = "<group>"; };
|
||||||
7AEFC3BD2529D3CC00BADFB2 /* ConfigurableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = "<group>"; };
|
7AEFC3BD2529D3CC00BADFB2 /* ConfigurableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = "<group>"; };
|
||||||
7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AutoCatCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AutoCatCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@ -923,7 +921,6 @@
|
|||||||
7A813DC7250B5C6E00CC93B9 /* Location */ = {
|
7A813DC7250B5C6E00CC93B9 /* Location */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
7AE26A3424F31B0700625033 /* EventsController.swift */,
|
|
||||||
7ADF6C94250D037700F237B2 /* ShowEventController.swift */,
|
7ADF6C94250D037700F237B2 /* ShowEventController.swift */,
|
||||||
7ADF6C9E251201D200F237B2 /* GlobalEventsController.swift */,
|
7ADF6C9E251201D200F237B2 /* GlobalEventsController.swift */,
|
||||||
);
|
);
|
||||||
@ -1328,7 +1325,6 @@
|
|||||||
7A2E11292CCE395300E5CA17 /* OptionalDatePicker.swift in Sources */,
|
7A2E11292CCE395300E5CA17 /* OptionalDatePicker.swift in Sources */,
|
||||||
7A761C0B267E8FF90005F28F /* Error.swift in Sources */,
|
7A761C0B267E8FF90005F28F /* Error.swift in Sources */,
|
||||||
7AC3555029696D5A00889457 /* NewNumberController.swift in Sources */,
|
7AC3555029696D5A00889457 /* NewNumberController.swift in Sources */,
|
||||||
7AE26A3524F31B0700625033 /* EventsController.swift in Sources */,
|
|
||||||
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */,
|
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */,
|
||||||
7AF860702CBAA24500954D2F /* NavigationLink.swift in Sources */,
|
7AF860702CBAA24500954D2F /* NavigationLink.swift in Sources */,
|
||||||
7AB9FE262D08C2D7005DE374 /* EventsCoordinator.swift in Sources */,
|
7AB9FE262D08C2D7005DE374 /* EventsCoordinator.swift in Sources */,
|
||||||
@ -1693,7 +1689,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 144;
|
CURRENT_PROJECT_VERSION = 145;
|
||||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
||||||
@ -1720,7 +1716,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 144;
|
CURRENT_PROJECT_VERSION = 145;
|
||||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
||||||
|
|||||||
@ -8,96 +8,6 @@
|
|||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Events-->
|
|
||||||
<scene sceneID="pPZ-gs-kHF">
|
|
||||||
<objects>
|
|
||||||
<viewController storyboardIdentifier="EventsController" title="Events" extendedLayoutIncludesOpaqueBars="YES" id="DmF-8j-ae3" customClass="EventsController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
|
|
||||||
<view key="view" contentMode="scaleToFill" id="mYm-sh-pSj">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<subviews>
|
|
||||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="ytQ-Th-luv">
|
|
||||||
<rect key="frame" x="0.0" y="20" width="375" height="647"/>
|
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
||||||
<prototypes>
|
|
||||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="EventCell" id="QIb-Hv-tvk" customClass="EventCell" customModule="AutoCat" customModuleProvider="target">
|
|
||||||
<rect key="frame" x="0.0" y="50" width="375" height="437.5"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QIb-Hv-tvk" id="Ypt-ch-fGT">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="437.5"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<subviews>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HP8-oO-yhP">
|
|
||||||
<rect key="frame" x="16" y="8" width="343" height="421.5"/>
|
|
||||||
<subviews>
|
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="k4Z-KM-byE">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="335" height="421.5"/>
|
|
||||||
<subviews>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xcQ-Wz-gJ0">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="335" height="201"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleBody"/>
|
|
||||||
<nil key="textColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1tQ-zM-6T9">
|
|
||||||
<rect key="frame" x="0.0" y="209" width="335" height="212.5"/>
|
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
|
||||||
<nil key="highlightedColor"/>
|
|
||||||
</label>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="750" verticalHuggingPriority="251" image="person" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="CFI-xa-eLs">
|
|
||||||
<rect key="frame" x="343" y="1" width="0.0" height="419"/>
|
|
||||||
</imageView>
|
|
||||||
</subviews>
|
|
||||||
</stackView>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="HP8-oO-yhP" firstAttribute="leading" secondItem="Ypt-ch-fGT" secondAttribute="leading" constant="16" id="BX3-sO-2mI"/>
|
|
||||||
<constraint firstItem="HP8-oO-yhP" firstAttribute="top" secondItem="Ypt-ch-fGT" secondAttribute="top" constant="8" id="kUQ-n4-izs"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="HP8-oO-yhP" secondAttribute="trailing" constant="16" id="nGB-VN-Sdx"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="HP8-oO-yhP" secondAttribute="bottom" constant="8" id="pFY-Uy-LSv"/>
|
|
||||||
</constraints>
|
|
||||||
</tableViewCellContentView>
|
|
||||||
<connections>
|
|
||||||
<outlet property="address" destination="xcQ-Wz-gJ0" id="k6e-Yz-MEB"/>
|
|
||||||
<outlet property="date" destination="1tQ-zM-6T9" id="DBs-dL-CmY"/>
|
|
||||||
<outlet property="userImageView" destination="CFI-xa-eLs" id="2QW-xC-mfU"/>
|
|
||||||
</connections>
|
|
||||||
</tableViewCell>
|
|
||||||
</prototypes>
|
|
||||||
<connections>
|
|
||||||
<outlet property="dataSource" destination="DmF-8j-ae3" id="ayM-aB-LZb"/>
|
|
||||||
<outlet property="delegate" destination="DmF-8j-ae3" id="O5y-AS-NK0"/>
|
|
||||||
</connections>
|
|
||||||
</tableView>
|
|
||||||
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" mapType="standard" showsCompass="NO" showsScale="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3Ru-VE-szI">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
|
||||||
</mapView>
|
|
||||||
</subviews>
|
|
||||||
<viewLayoutGuide key="safeArea" id="9R5-6n-B3H"/>
|
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="9R5-6n-B3H" firstAttribute="trailing" secondItem="ytQ-Th-luv" secondAttribute="trailing" id="UuJ-8s-LEB"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="3Ru-VE-szI" secondAttribute="bottom" id="asd-Fg-84K"/>
|
|
||||||
<constraint firstItem="3Ru-VE-szI" firstAttribute="leading" secondItem="mYm-sh-pSj" secondAttribute="leading" id="bOP-2E-BEk"/>
|
|
||||||
<constraint firstItem="3Ru-VE-szI" firstAttribute="top" secondItem="mYm-sh-pSj" secondAttribute="top" id="cmd-fX-3Qa"/>
|
|
||||||
<constraint firstItem="ytQ-Th-luv" firstAttribute="top" secondItem="9R5-6n-B3H" secondAttribute="top" id="mmu-vo-0BG"/>
|
|
||||||
<constraint firstItem="ytQ-Th-luv" firstAttribute="leading" secondItem="9R5-6n-B3H" secondAttribute="leading" id="pDL-PN-vlh"/>
|
|
||||||
<constraint firstItem="9R5-6n-B3H" firstAttribute="bottom" secondItem="ytQ-Th-luv" secondAttribute="bottom" id="pVh-Q9-Gqi"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="3Ru-VE-szI" secondAttribute="trailing" id="w0g-Ng-mkW"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
<connections>
|
|
||||||
<outlet property="map" destination="3Ru-VE-szI" id="rYQ-5P-Kxr"/>
|
|
||||||
<outlet property="tableView" destination="ytQ-Th-luv" id="7Mf-aR-TGJ"/>
|
|
||||||
</connections>
|
|
||||||
</viewController>
|
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="heB-JE-Wi6" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="1881" y="1660"/>
|
|
||||||
</scene>
|
|
||||||
<!--Search Controller-->
|
<!--Search Controller-->
|
||||||
<scene sceneID="3Md-yW-a0R">
|
<scene sceneID="3Md-yW-a0R">
|
||||||
<objects>
|
<objects>
|
||||||
@ -780,7 +690,6 @@
|
|||||||
<image name="exclamationmark.arrow.triangle.2.circlepath" catalog="system" width="128" height="117"/>
|
<image name="exclamationmark.arrow.triangle.2.circlepath" catalog="system" width="128" height="117"/>
|
||||||
<image name="line.horizontal.3.decrease" catalog="system" width="128" height="73"/>
|
<image name="line.horizontal.3.decrease" catalog="system" width="128" height="73"/>
|
||||||
<image name="map" catalog="system" width="128" height="112"/>
|
<image name="map" catalog="system" width="128" height="112"/>
|
||||||
<image name="person" catalog="system" width="128" height="121"/>
|
|
||||||
<image name="play.fill" catalog="system" width="120" height="128"/>
|
<image name="play.fill" catalog="system" width="120" height="128"/>
|
||||||
<image name="plus" catalog="system" width="128" height="113"/>
|
<image name="plus" catalog="system" width="128" height="113"/>
|
||||||
<image name="record" width="31" height="31"/>
|
<image name="record" width="31" height="31"/>
|
||||||
|
|||||||
@ -1,418 +0,0 @@
|
|||||||
import UIKit
|
|
||||||
import MapKit
|
|
||||||
import RealmSwift
|
|
||||||
import PKHUD
|
|
||||||
import MobileCoreServices
|
|
||||||
import ExceptionCatcher
|
|
||||||
import AutoCatCore
|
|
||||||
|
|
||||||
class EventPin: NSObject, MKAnnotation {
|
|
||||||
var coordinate: CLLocationCoordinate2D
|
|
||||||
var title: String?
|
|
||||||
var subtitle: String?
|
|
||||||
var id: String
|
|
||||||
|
|
||||||
init(id: String, coordinate: CLLocationCoordinate2D, title: String?, subtitle: String) {
|
|
||||||
self.coordinate = coordinate
|
|
||||||
self.title = title
|
|
||||||
self.subtitle = subtitle
|
|
||||||
self.id = id
|
|
||||||
}
|
|
||||||
|
|
||||||
convenience init(event: VehicleEventDto) {
|
|
||||||
let coordinate = CLLocationCoordinate2D(latitude: event.latitude, longitude: event.longitude)
|
|
||||||
let address = event.address ?? "\(event.latitude), \(event.longitude)"
|
|
||||||
let date = Date(timeIntervalSince1970: event.date)
|
|
||||||
let formatter = DateFormatter()
|
|
||||||
formatter.dateStyle = .medium
|
|
||||||
formatter.timeStyle = .short
|
|
||||||
let dateStr = formatter.string(from: date)
|
|
||||||
|
|
||||||
if let number = event.number {
|
|
||||||
self.init(id: event.id, coordinate: coordinate, title: number, subtitle: dateStr)
|
|
||||||
} else {
|
|
||||||
self.init(id: event.id, coordinate: coordinate, title: dateStr, subtitle: address)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum EventsMode {
|
|
||||||
case map
|
|
||||||
case list
|
|
||||||
}
|
|
||||||
|
|
||||||
class EventsController: UIViewController, UITableViewDataSource, UITableViewDelegate, MKMapViewDelegate {
|
|
||||||
|
|
||||||
@IBOutlet weak var map: MKMapView!
|
|
||||||
@IBOutlet weak var tableView: UITableView!
|
|
||||||
|
|
||||||
@Service var settingsService: SettingsServiceProtocol
|
|
||||||
|
|
||||||
var modeButton: UIBarButtonItem!
|
|
||||||
var addButton: UIBarButtonItem!
|
|
||||||
var pasteButton: UIBarButtonItem!
|
|
||||||
var mode: EventsMode = .map
|
|
||||||
|
|
||||||
public var vehicle: VehicleDto? {
|
|
||||||
didSet {
|
|
||||||
if self.isViewLoaded {
|
|
||||||
self.updateInterface()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var vehicleUpdated: ((VehicleDto) -> Void)?
|
|
||||||
|
|
||||||
private var pins: [EventPin] = []
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
|
||||||
super.viewDidLoad()
|
|
||||||
|
|
||||||
self.title = self.vehicle?.getNumber() ?? NSLocalizedString("Events", comment: "")
|
|
||||||
|
|
||||||
#if targetEnvironment(macCatalyst)
|
|
||||||
|
|
||||||
if #available(OSX 11.0, *) {
|
|
||||||
self.map.showsCompass = true
|
|
||||||
}
|
|
||||||
self.map.showsZoomControls = true
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
self.modeButton = UIBarButtonItem(image: UIImage(systemName: "list.bullet"), style: .plain, target: self, action: #selector(switchMode(_:)))
|
|
||||||
self.addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addEvent(_:)))
|
|
||||||
self.pasteButton = UIBarButtonItem(image: UIImage(systemName: "doc.on.clipboard"), style: .plain, target: self, action: #selector(pasteEvent(_:)))
|
|
||||||
self.setupBarButtonItems()
|
|
||||||
self.map.delegate = self
|
|
||||||
|
|
||||||
self.updateInterface()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
|
||||||
super.viewDidAppear(animated)
|
|
||||||
self.setupBarButtonItems()
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateInterface() {
|
|
||||||
if let vehicle = self.vehicle {
|
|
||||||
self.pins = vehicle.events.map(EventPin.init(event:))
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.pins.isEmpty {
|
|
||||||
self.map.removeAnnotations(self.map.annotations)
|
|
||||||
self.map.addAnnotations(self.pins)
|
|
||||||
self.map.centerOnPins()
|
|
||||||
} else {
|
|
||||||
self.map.showsUserLocation = true
|
|
||||||
}
|
|
||||||
|
|
||||||
self.tableView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func switchMode(_ sender: UIBarButtonItem) {
|
|
||||||
switch self.mode {
|
|
||||||
case .map:
|
|
||||||
self.mode = .list
|
|
||||||
self.tableView.reloadData()
|
|
||||||
self.tableView.isHidden = false
|
|
||||||
self.map.isHidden = true
|
|
||||||
self.modeButton.image = UIImage(systemName: "map")
|
|
||||||
case .list:
|
|
||||||
self.mode = .map
|
|
||||||
self.tableView.isHidden = true
|
|
||||||
self.map.isHidden = false
|
|
||||||
self.modeButton.image = UIImage(systemName: "list.bullet")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - UITableViewDataSource
|
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
|
||||||
return self.vehicle?.events.count ?? 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
|
||||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: "EventCell", for: indexPath) as? EventCell else {
|
|
||||||
return UITableViewCell()
|
|
||||||
}
|
|
||||||
|
|
||||||
if let event = self.vehicle?.events[indexPath.row] {
|
|
||||||
cell.configure(with: event)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cell
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - UITableViewDelegate
|
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
|
||||||
guard let vehicle = self.vehicle else {
|
|
||||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let event = vehicle.events[indexPath.row]
|
|
||||||
|
|
||||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
|
|
||||||
|
|
||||||
let copy = UIAction(title: NSLocalizedString("Copy", comment: ""),
|
|
||||||
image: UIImage(systemName: "doc.on.doc"),
|
|
||||||
handler: { _ in self.copyEvent(event: event) })
|
|
||||||
|
|
||||||
let share = UIAction(title: NSLocalizedString("Share", comment: ""),
|
|
||||||
image: UIImage(systemName: "square.and.arrow.up"),
|
|
||||||
handler: { _ in self.shareEvent(event: event) })
|
|
||||||
|
|
||||||
let edit = UIAction(title: NSLocalizedString("Edit", comment: ""),
|
|
||||||
image: UIImage(systemName: "pencil"),
|
|
||||||
handler: { _ in self.editEvent(event: event) })
|
|
||||||
|
|
||||||
let delete = UIAction(title: NSLocalizedString("Delete", comment: ""),
|
|
||||||
image: UIImage(systemName: "trash"),
|
|
||||||
attributes: .destructive,
|
|
||||||
handler: { _ in self.deleteEvent(event: event) })
|
|
||||||
|
|
||||||
let openApple = UIAction(title: NSLocalizedString("Apple Maps", comment: ""),
|
|
||||||
image: UIImage(systemName: "map"),
|
|
||||||
handler: { _ in self.openInAppleMaps(event: event) })
|
|
||||||
|
|
||||||
let openYandex = UIAction(title: NSLocalizedString("Yandex Maps", comment: ""),
|
|
||||||
image: UIImage(systemName: "map"),
|
|
||||||
handler: { _ in self.openInYandexMaps(event: event) })
|
|
||||||
|
|
||||||
let openMenu: UIMenuElement
|
|
||||||
if let yandexUrl = URL(string: "yandexmaps://"),
|
|
||||||
UIApplication.shared.canOpenURL(yandexUrl)
|
|
||||||
{
|
|
||||||
openMenu = UIMenu(title: NSLocalizedString("Open in ...", comment: ""),
|
|
||||||
children: [openApple, openYandex])
|
|
||||||
} else {
|
|
||||||
openApple.title = NSLocalizedString("Open in Apple Maps", comment: "")
|
|
||||||
openMenu = openApple
|
|
||||||
}
|
|
||||||
|
|
||||||
return UIMenu(title: NSLocalizedString("Actions", comment: ""), children: [copy, share, edit, openMenu, delete])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
|
||||||
guard let vehicle = self.vehicle else {
|
|
||||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
let event = vehicle.events[indexPath.row]
|
|
||||||
|
|
||||||
let copy = UIContextualAction(style: .normal, title: NSLocalizedString("Copy", comment: "")) { action, view, completion in
|
|
||||||
self.copyEvent(event: event)
|
|
||||||
completion(true)
|
|
||||||
}
|
|
||||||
copy.image = UIImage(systemName: "doc.on.doc")
|
|
||||||
copy.backgroundColor = .systemBlue
|
|
||||||
|
|
||||||
let delete = UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { action, view, completion in
|
|
||||||
self.deleteEvent(event: event, completion: completion)
|
|
||||||
}
|
|
||||||
delete.image = UIImage(systemName: "trash")
|
|
||||||
|
|
||||||
let edit = UIContextualAction(style: .normal, title: NSLocalizedString("Edit", comment: "")) { action, view, completion in
|
|
||||||
self.editEvent(event: event)
|
|
||||||
completion(true)
|
|
||||||
}
|
|
||||||
edit.image = UIImage(systemName: "pencil")
|
|
||||||
edit.backgroundColor = .systemBlue
|
|
||||||
|
|
||||||
let configuration = UISwipeActionsConfiguration(actions: [delete, edit, copy])
|
|
||||||
configuration.performsFirstActionWithFullSwipe = false
|
|
||||||
return configuration
|
|
||||||
}
|
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
||||||
guard let event = self.vehicle?.events[indexPath.row],
|
|
||||||
let pin = pins.first(where: { $0.id == event.id }) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
|
||||||
switchMode(modeButton)
|
|
||||||
|
|
||||||
map.setCenter(pin.coordinate, animated: true)
|
|
||||||
map.selectAnnotation(pin, animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Event actions
|
|
||||||
|
|
||||||
func deleteEvent(event: VehicleEventDto, completion: ((Bool) -> Void)? = nil) {
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
HUD.show(.progress)
|
|
||||||
let vehicle = try await ApiService.shared.remove(event: event.id)
|
|
||||||
let result = self.update(vehicle: vehicle)
|
|
||||||
completion?(result)
|
|
||||||
} catch {
|
|
||||||
completion?(false)
|
|
||||||
HUD.show(error: error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func editEvent(event: VehicleEventDto) {
|
|
||||||
|
|
||||||
if let navigationController {
|
|
||||||
let coordinator = LocationEditCoordinator(navController: navigationController)
|
|
||||||
Task {
|
|
||||||
if let event = await coordinator.start(event: event) {
|
|
||||||
do {
|
|
||||||
HUD.show(.progress)
|
|
||||||
let vehicle = try await ApiService.shared.edit(event: event)
|
|
||||||
self.update(vehicle: vehicle)
|
|
||||||
} catch {
|
|
||||||
HUD.show(error: error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyEvent(event: VehicleEventDto) {
|
|
||||||
var items: [String: Any] = [:]
|
|
||||||
|
|
||||||
if let url = event.getMapLink() {
|
|
||||||
items[kUTTypeURL as String] = url
|
|
||||||
//UIPasteboard.general.setValue(url, forPasteboardType: kUTTypeURL as String)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let data = try? JSONEncoder().encode(event) {
|
|
||||||
items["pro.aliencat.vehicle.event"] = data
|
|
||||||
//UIPasteboard.general.setData(data, forPasteboardType: "pro.aliencat.vehicle.event")
|
|
||||||
}
|
|
||||||
|
|
||||||
if !items.isEmpty {
|
|
||||||
UIPasteboard.general.items = [items]
|
|
||||||
}
|
|
||||||
|
|
||||||
self.setupBarButtonItems()
|
|
||||||
}
|
|
||||||
|
|
||||||
func shareEvent(event: VehicleEventDto) {
|
|
||||||
guard let url = event.getMapLink() else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
|
||||||
self.present(controller, animated: true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func openInAppleMaps(event: VehicleEventDto) {
|
|
||||||
let coordinates = CLLocationCoordinate2D(latitude: event.latitude,
|
|
||||||
longitude: event.longitude)
|
|
||||||
let placemark = MKPlacemark(coordinate: coordinates)
|
|
||||||
let mapItem = MKMapItem(placemark: placemark)
|
|
||||||
mapItem.openInMaps()
|
|
||||||
}
|
|
||||||
|
|
||||||
func openInYandexMaps(event: VehicleEventDto) {
|
|
||||||
guard let url = URL(string: "yandexmaps://maps.yandex.ru/?pt=\(event.longitude),\(event.latitude)&z=12") else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
UIApplication.shared.open(url)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func addEvent(_ sender: UIBarButtonItem) {
|
|
||||||
guard let vehicle = self.vehicle else {
|
|
||||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let navigationController {
|
|
||||||
let coordinator = LocationEditCoordinator(navController: navigationController)
|
|
||||||
|
|
||||||
Task {
|
|
||||||
let newEvent = VehicleEventDto(lat: 0, lon: 0, addedBy: settingsService.user.email)
|
|
||||||
if let event = await coordinator.start(event: newEvent) {
|
|
||||||
do {
|
|
||||||
HUD.show(.progress)
|
|
||||||
let vehicle = try await ApiService.shared.add(event: event, to: vehicle.getNumber())
|
|
||||||
self.update(vehicle: vehicle)
|
|
||||||
} catch {
|
|
||||||
HUD.show(error: error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func pasteEvent(_ sender: UIBarButtonItem) {
|
|
||||||
guard let vehicle = self.vehicle else {
|
|
||||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
guard let data = UIPasteboard.general.data(forPasteboardType: "pro.aliencat.vehicle.event") else { return }
|
|
||||||
|
|
||||||
do {
|
|
||||||
let event = try JSONDecoder().decode(VehicleEventDto.self, from: data)
|
|
||||||
let formatter = DateFormatter()
|
|
||||||
formatter.dateStyle = .medium
|
|
||||||
formatter.timeStyle = .medium
|
|
||||||
let msg = formatter.string(from: Date(timeIntervalSince1970: event.date)) + "\n" + event.getLocationString()
|
|
||||||
|
|
||||||
let alert = UIAlertController(title: NSLocalizedString("Paste event", comment: "from clipboard"), message: msg, preferredStyle: .alert)
|
|
||||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Paste", comment: "from clipboard"), style: .default, handler: { action in
|
|
||||||
Task {
|
|
||||||
do {
|
|
||||||
HUD.show(.progress)
|
|
||||||
var newEvent = event
|
|
||||||
newEvent.id = UUID().uuidString
|
|
||||||
let vehicle = try await ApiService.shared.add(event: newEvent, to: vehicle.getNumber())
|
|
||||||
self.update(vehicle: vehicle)
|
|
||||||
} catch {
|
|
||||||
HUD.show(error: error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil))
|
|
||||||
self.present(alert, animated: true)
|
|
||||||
} catch {
|
|
||||||
print(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupBarButtonItems() {
|
|
||||||
let pasteVisible = UIPasteboard.general.data(forPasteboardType: "pro.aliencat.vehicle.event") != nil
|
|
||||||
self.navigationItem.rightBarButtonItems = pasteVisible ? [self.modeButton, self.addButton, self.pasteButton] : [self.modeButton, self.addButton]
|
|
||||||
}
|
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
func update(vehicle: VehicleDto) -> Bool {
|
|
||||||
do {
|
|
||||||
let realm = try Realm()
|
|
||||||
if realm.object(ofType: Vehicle.self, forPrimaryKey: vehicle.getNumber()) != nil {
|
|
||||||
try ExceptionCatcher.catch {
|
|
||||||
try realm.write {
|
|
||||||
realm.add(Vehicle(dto: vehicle), update: .all)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.vehicle?.events = vehicle.events.sorted { $0.date > $1.date }
|
|
||||||
self.vehicleUpdated?(vehicle)
|
|
||||||
|
|
||||||
HUD.hide()
|
|
||||||
return true
|
|
||||||
} catch {
|
|
||||||
HUD.hide()
|
|
||||||
self.show(error: error)
|
|
||||||
print(error)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - MKMapViewDelegate
|
|
||||||
|
|
||||||
public func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
|
|
||||||
let region = MKCoordinateRegion(center: userLocation.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000)
|
|
||||||
self.map.setRegion(region, animated: true)
|
|
||||||
self.map.showsUserLocation = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,6 +3,36 @@ import MapKit
|
|||||||
import PKHUD
|
import PKHUD
|
||||||
import AutoCatCore
|
import AutoCatCore
|
||||||
|
|
||||||
|
class EventPin: NSObject, MKAnnotation {
|
||||||
|
var coordinate: CLLocationCoordinate2D
|
||||||
|
var title: String?
|
||||||
|
var subtitle: String?
|
||||||
|
var id: String
|
||||||
|
|
||||||
|
init(id: String, coordinate: CLLocationCoordinate2D, title: String?, subtitle: String) {
|
||||||
|
self.coordinate = coordinate
|
||||||
|
self.title = title
|
||||||
|
self.subtitle = subtitle
|
||||||
|
self.id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
convenience init(event: VehicleEventDto) {
|
||||||
|
let coordinate = CLLocationCoordinate2D(latitude: event.latitude, longitude: event.longitude)
|
||||||
|
let address = event.address ?? "\(event.latitude), \(event.longitude)"
|
||||||
|
let date = Date(timeIntervalSince1970: event.date)
|
||||||
|
let formatter = DateFormatter()
|
||||||
|
formatter.dateStyle = .medium
|
||||||
|
formatter.timeStyle = .short
|
||||||
|
let dateStr = formatter.string(from: date)
|
||||||
|
|
||||||
|
if let number = event.number {
|
||||||
|
self.init(id: event.id, coordinate: coordinate, title: number, subtitle: dateStr)
|
||||||
|
} else {
|
||||||
|
self.init(id: event.id, coordinate: coordinate, title: dateStr, subtitle: address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class GlobalEventsController: UIViewController {
|
class GlobalEventsController: UIViewController {
|
||||||
|
|
||||||
@IBOutlet weak var map: MKMapView!
|
@IBOutlet weak var map: MKMapView!
|
||||||
|
|||||||
@ -138,9 +138,13 @@ struct EventsScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
EventsScreen(viewModel: .init(apiService: MockApiServiceProtocol(),
|
EventsScreen(viewModel: .init(apiService: MockApiServiceProtocol(),
|
||||||
storageService: MockStorageServiceProtocol(),
|
storageService: MockStorageServiceProtocol(),
|
||||||
settingsService: MockSettingsServiceProtocol(),
|
settingsService: MockSettingsServiceProtocol(),
|
||||||
vehicle: .preview))
|
vehicle: .preview))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -89,9 +89,11 @@ class EventsViewModel: ACHudContainer {
|
|||||||
|
|
||||||
func addNewEvent() async {
|
func addNewEvent() async {
|
||||||
|
|
||||||
let newEvent = VehicleEventDto(lat: 0, lon: 0, addedBy: settingsService.user.email)
|
let emptyEvent = VehicleEventDto(lat: 0, lon: 0, addedBy: settingsService.user.email)
|
||||||
|
if let newEvent = await coordinator?.editEvent(event: emptyEvent) {
|
||||||
await addEvent(newEvent)
|
await addEvent(newEvent)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func deleteEvent(_ event: EventModel) async {
|
func deleteEvent(_ event: EventModel) async {
|
||||||
|
|
||||||
|
|||||||
@ -119,9 +119,13 @@ struct FiltersScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
FiltersScreen(viewModel: .init(
|
FiltersScreen(viewModel: .init(
|
||||||
apiService: MockApiServiceProtocol(),
|
apiService: MockApiServiceProtocol(),
|
||||||
filter: Filter()
|
filter: Filter()
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -86,6 +86,8 @@ struct NotesScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
|
|
||||||
var vehicle = VehicleDto()
|
var vehicle = VehicleDto()
|
||||||
@ -104,3 +106,5 @@ struct NotesScreen: View {
|
|||||||
|
|
||||||
return NotesScreen(viewModel: vm)
|
return NotesScreen(viewModel: vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -125,6 +125,8 @@ struct ReportScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
ReportScreen(viewModel: .init(
|
ReportScreen(viewModel: .init(
|
||||||
apiService: MockApiServiceProtocol(),
|
apiService: MockApiServiceProtocol(),
|
||||||
@ -134,3 +136,5 @@ struct ReportScreen: View {
|
|||||||
isPersistent: false
|
isPersistent: false
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -87,6 +87,10 @@ struct SettingsScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
#Preview {
|
#Preview {
|
||||||
SettingsScreen(viewModel: .init(settingsService: MockSettingsServiceProtocol()))
|
SettingsScreen(viewModel: .init(settingsService: MockSettingsServiceProtocol()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user