Adding/removing/editing events

This commit is contained in:
Selim Mustafaev 2020-09-11 19:27:32 +03:00
parent 3332d12b05
commit 734fc5321f
19 changed files with 731 additions and 96 deletions

View File

@ -77,6 +77,10 @@
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */; };
7A813DBE2506A57100CC93B9 /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A813DBD2506A57100CC93B9 /* AuthenticationServices.framework */; };
7A813DC12508C4D900CC93B9 /* ExceptionCatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */; };
7A813DC32508EE4F00CC93B9 /* EventCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A813DC22508EE4F00CC93B9 /* EventCell.swift */; };
7A813DC5250AAF3C00CC93B9 /* LocationEditController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A813DC4250AAF3C00CC93B9 /* LocationEditController.swift */; };
7A813DC9250B5C9700CC93B9 /* LocationRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A813DC8250B5C9700CC93B9 /* LocationRow.swift */; };
7A813DCB250B5DC900CC93B9 /* LocationPickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A813DCA250B5DC900CC93B9 /* LocationPickerController.swift */; };
7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8A2208248D10EC0073DFD9 /* ResizeImage.swift */; };
7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A8A220A248D67B60073DFD9 /* VehicleReportImage.swift */; };
7A96AE2A246AFD6200297C33 /* Eureka in Frameworks */ = {isa = PBXBuildFile; productRef = 7A96AE29246AFD6200297C33 /* Eureka */; };
@ -88,6 +92,7 @@
7AB562BA249C9E9B00473D53 /* Region.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB562B9249C9E9B00473D53 /* Region.swift */; };
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8B2435C38700258F61 /* CustomTextField.swift */; };
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; };
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C92250B954900F237B2 /* Navigation.swift */; };
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */; };
7AE26A3524F31B0700625033 /* EventsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3424F31B0700625033 /* EventsController.swift */; };
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFE727240455E200910EB7 /* SettingsController.swift */; };
@ -160,6 +165,10 @@
7A7547DC2403180A004E8406 /* SectionHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SectionHeader.xib; sourceTree = "<group>"; };
7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehiclePhotoCell.swift; sourceTree = "<group>"; };
7A813DBD2506A57100CC93B9 /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/AuthenticationServices.framework; sourceTree = DEVELOPER_DIR; };
7A813DC22508EE4F00CC93B9 /* EventCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventCell.swift; sourceTree = "<group>"; };
7A813DC4250AAF3C00CC93B9 /* LocationEditController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationEditController.swift; sourceTree = "<group>"; };
7A813DC8250B5C9700CC93B9 /* LocationRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationRow.swift; sourceTree = "<group>"; };
7A813DCA250B5DC900CC93B9 /* LocationPickerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationPickerController.swift; sourceTree = "<group>"; };
7A8A2208248D10EC0073DFD9 /* ResizeImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResizeImage.swift; sourceTree = "<group>"; };
7A8A220A248D67B60073DFD9 /* VehicleReportImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleReportImage.swift; sourceTree = "<group>"; };
7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ATGMediaBrowser.framework; path = Carthage/Build/iOS/ATGMediaBrowser.framework; sourceTree = "<group>"; };
@ -171,6 +180,7 @@
7AB562B9249C9E9B00473D53 /* Region.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Region.swift; sourceTree = "<group>"; };
7AB67E8B2435C38700258F61 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
7AB67E8D2435D1A000258F61 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; };
7ADF6C92250B954900F237B2 /* Navigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Navigation.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>"; };
7AEFE727240455E200910EB7 /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
@ -248,6 +258,7 @@
7A11471423FDEAF800B424AF /* Controllers */ = {
isa = PBXGroup;
children = (
7A813DC7250B5C6E00CC93B9 /* Location */,
7A11471523FDEB2A00B424AF /* MainSplitController.swift */,
7A11471723FDEBFA00B424AF /* ReportController.swift */,
7A11471923FE839000B424AF /* AuthController.swift */,
@ -259,7 +270,6 @@
7A33381024990DAE00D878F1 /* FiltersController.swift */,
7A27ADC6249D43210035F39E /* RegionsController.swift */,
7A27ADF2249F8B650035F39E /* RecordsController.swift */,
7AE26A3424F31B0700625033 /* EventsController.swift */,
);
path = Controllers;
sourceTree = "<group>";
@ -329,6 +339,7 @@
7A659B5A24A3768A0043A0F2 /* Substrings.swift */,
7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */,
7A21112924FC3D7E003BBF6F /* AudioEngine.swift */,
7ADF6C92250B954900F237B2 /* Navigation.swift */,
);
path = Extensions;
sourceTree = "<group>";
@ -354,6 +365,7 @@
7A7547DC2403180A004E8406 /* SectionHeader.xib */,
7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */,
7A1090E724A394F100B4F0B2 /* AudioRecordCell.swift */,
7A813DC22508EE4F00CC93B9 /* EventCell.swift */,
);
path = Cells;
sourceTree = "<group>";
@ -402,6 +414,17 @@
path = Fonts;
sourceTree = "<group>";
};
7A813DC7250B5C6E00CC93B9 /* Location */ = {
isa = PBXGroup;
children = (
7A813DC4250AAF3C00CC93B9 /* LocationEditController.swift */,
7AE26A3424F31B0700625033 /* EventsController.swift */,
7A813DC8250B5C9700CC93B9 /* LocationRow.swift */,
7A813DCA250B5DC900CC93B9 /* LocationPickerController.swift */,
);
path = Location;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -512,7 +535,9 @@
7A64AE822469E16100ABE48E /* IHProgressHUD.swift in Sources */,
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */,
7A27ADF924A09CAD0035F39E /* CocoaError.swift in Sources */,
7A813DC9250B5C9700CC93B9 /* LocationRow.swift in Sources */,
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */,
7A813DC32508EE4F00CC93B9 /* EventCell.swift in Sources */,
7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */,
7AB562BA249C9E9B00473D53 /* Region.swift in Sources */,
7A659B5924A2B1BA0043A0F2 /* AudioRecord.swift in Sources */,
@ -549,12 +574,14 @@
7A11474723FF2AA500B424AF /* User.swift in Sources */,
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */,
7AF58D3124029E1000CE01A0 /* VehicleHeaderCell.swift in Sources */,
7A813DC5250AAF3C00CC93B9 /* LocationEditController.swift in Sources */,
7A43F9F8246C8A6200BA5B49 /* JWT.swift in Sources */,
7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */,
7A488C3F24A74B990054D0B2 /* RealmBindObserver.swift in Sources */,
7AAE6AD324CDDF950023860B /* VehicleEvent.swift in Sources */,
7A11470323FDE7E500B424AF /* SceneDelegate.swift in Sources */,
7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */,
7A813DCB250B5DC900CC93B9 /* LocationPickerController.swift in Sources */,
7A11474423FF06CA00B424AF /* Api.swift in Sources */,
7A488C3D24A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift in Sources */,
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */,
@ -565,6 +592,7 @@
7A05161A2414FF0900FC55AC /* DateSection.swift in Sources */,
7A333814249A532400D878F1 /* Filter.swift in Sources */,
7A11474B23FF368B00B424AF /* Settings.swift in Sources */,
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */,
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
7A64AE812469E16100ABE48E /* ProgressAnimatedView.swift in Sources */,
@ -715,7 +743,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 28;
CURRENT_PROJECT_VERSION = 29;
DEVELOPMENT_TEAM = 46DTTB8X4S;
INFOPLIST_FILE = AutoCat/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@ -737,7 +765,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 28;
CURRENT_PROJECT_VERSION = 29;
DEVELOPMENT_TEAM = 46DTTB8X4S;
INFOPLIST_FILE = AutoCat/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;

View File

@ -23,7 +23,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let config = Realm.Configuration(
schemaVersion: 15,
schemaVersion: 16,
migrationBlock: { migration, oldSchemaVersion in
if oldSchemaVersion <= 3 {
var numbers: [String] = []

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "map_pin@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "map_pin@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -227,27 +227,94 @@
<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="0.0" width="375" height="667"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<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="28" width="375" height="63"/>
<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="63"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HP8-oO-yhP">
<rect key="frame" x="8" y="8" width="359" height="47"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xcQ-Wz-gJ0">
<rect key="frame" x="0.0" y="0.0" width="359" height="20.5"/>
<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="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1tQ-zM-6T9">
<rect key="frame" x="0.0" y="28.5" width="359" height="18.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</stackView>
</subviews>
<constraints>
<constraint firstItem="HP8-oO-yhP" firstAttribute="leading" secondItem="Ypt-ch-fGT" secondAttribute="leading" constant="8" 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="8" 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"/>
</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" translatesAutoresizingMaskIntoConstraints="NO" id="3Ru-VE-szI">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
</mapView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstAttribute="bottomMargin" secondItem="3Ru-VE-szI" secondAttribute="bottom" id="asd-Fg-84K"/>
<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>
<viewLayoutGuide key="safeArea" id="9R5-6n-B3H"/>
</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>
<!--Location Edit Controller-->
<scene sceneID="Bjx-jy-Fp1">
<objects>
<viewController storyboardIdentifier="LocationEditController" id="HJt-oG-6ic" customClass="LocationEditController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="DJI-63-46l">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="yiT-Qb-YfV"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="xxt-kh-jhI" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2557.5999999999999" y="1658.3208395802101"/>
</scene>
<!--Search Controller-->
<scene sceneID="3Md-yW-a0R">
<objects>
@ -261,14 +328,14 @@
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="VehicleCell" id="VEP-QD-i6y" customClass="VehicleCell" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="85.5"/>
<rect key="frame" x="0.0" y="28" width="375" height="85"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VEP-QD-i6y" id="8hH-8I-XLB">
<rect key="frame" x="0.0" y="0.0" width="375" height="85.5"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="85"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Kia (JF) Optima" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AQY-7N-q8D">
<rect key="frame" x="8" y="8" width="124" height="21.5"/>
<rect key="frame" x="8" y="8" width="124" height="21"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -280,7 +347,7 @@
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cvf-vM-QnT" customClass="PlateView" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="8" y="37.5" width="317" height="40"/>
<rect key="frame" x="8" y="37" width="317" height="40"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Xoz-Iw-PCU"/>

View File

@ -0,0 +1,26 @@
import UIKit
class EventCell: UITableViewCell {
@IBOutlet weak var address: UILabel!
@IBOutlet weak var date: UILabel!
let dateFormatter = DateFormatter()
override func awakeFromNib() {
super.awakeFromNib()
self.dateFormatter.dateStyle = .short
self.dateFormatter.timeStyle = .short
}
func configure(with event: VehicleEvent) {
if let addressString = event.address {
self.address.text = addressString
} else {
self.address.text = "Lat: \(event.latitude), Lon: \(event.longitude)"
}
let date = Date(timeIntervalSince1970: event.date)
self.date.text = self.dateFormatter.string(from: date)
}
}

View File

@ -1,68 +0,0 @@
import UIKit
import MapKit
class EventPin: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(coordinate: CLLocationCoordinate2D, title: String?, subtitle: String) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
}
}
class EventsController: UIViewController {
@IBOutlet weak var map: MKMapView!
public var events: [VehicleEvent] = [] {
didSet {
self.pins = self.events.map { event in
let coordinate = CLLocationCoordinate2D(latitude: event.latitude, longitude: event.longitude)
let subtitle = event.address ?? "\(event.latitude), \(event.longitude)"
let date = Date(timeIntervalSince1970: event.date)
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let title = formatter.string(from: date)
return EventPin(coordinate: coordinate, title: title, subtitle: subtitle)
}
}
}
private var pins: [EventPin] = []
override func viewDidLoad() {
super.viewDidLoad()
#if targetEnvironment(macCatalyst)
self.map.showsZoomControls = true
#endif
self.map.addAnnotations(self.pins)
self.centerMap()
}
func centerMap() {
var minLat = 0.0, maxLat = 0.0, minLon = 0.0, maxLon = 0.0
for event in self.events {
if event.latitude < minLat || minLat == 0 { minLat = event.latitude }
if event.latitude > maxLat || maxLat == 0 { maxLat = event.latitude }
if event.longitude < minLon || minLon == 0 { minLon = event.longitude }
if event.longitude > maxLon || maxLon == 0 { maxLon = event.longitude }
}
let center = CLLocationCoordinate2D(latitude: (minLat + maxLat)/2, longitude: (minLon + maxLon)/2)
let leftTop = CLLocation(latitude: minLat, longitude: minLon)
let rightBottom = CLLocation(latitude: maxLat, longitude: maxLon)
var diagonal = leftTop.distance(from: rightBottom)
if diagonal < 1000 {
diagonal = 1000
}
let region = MKCoordinateRegion(center: center, latitudinalMeters: diagonal, longitudinalMeters: diagonal)
self.map.setRegion(region, animated: true)
}
}

View File

@ -0,0 +1,251 @@
import UIKit
import MapKit
import RxSwift
import Realm
import RealmSwift
class EventPin: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(coordinate: CLLocationCoordinate2D, title: String?, subtitle: String) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
}
}
enum EventsMode {
case map
case list
}
class EventsController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var map: MKMapView!
@IBOutlet weak var tableView: UITableView!
let bag = DisposeBag()
var modeButton: UIBarButtonItem!
var addButton: UIBarButtonItem!
var mode: EventsMode = .map
public var vehicle: Vehicle? {
didSet {
if let vehicle = self.vehicle {
self.pins = vehicle.events.map { event in
let coordinate = CLLocationCoordinate2D(latitude: event.latitude, longitude: event.longitude)
let subtitle = event.address ?? "\(event.latitude), \(event.longitude)"
let date = Date(timeIntervalSince1970: event.date)
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let title = formatter.string(from: date)
return EventPin(coordinate: coordinate, title: title, subtitle: subtitle)
}
} else {
}
if self.isViewLoaded {
self.updateInterface()
}
}
}
private var pins: [EventPin] = []
override func viewDidLoad() {
super.viewDidLoad()
self.title = self.vehicle?.number ?? "Events"
#if targetEnvironment(macCatalyst)
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.navigationItem.rightBarButtonItems = [self.modeButton, self.addButton]
self.updateInterface()
}
func updateInterface() {
self.map.removeAnnotations(self.map.annotations)
self.map.addAnnotations(self.pins)
self.centerMap()
self.tableView.reloadData()
}
func centerMap() {
guard let vehicle = self.vehicle else { return }
var minLat = 0.0, maxLat = 0.0, minLon = 0.0, maxLon = 0.0
for event in vehicle.events {
if event.latitude < minLat || minLat == 0 { minLat = event.latitude }
if event.latitude > maxLat || maxLat == 0 { maxLat = event.latitude }
if event.longitude < minLon || minLon == 0 { minLon = event.longitude }
if event.longitude > maxLon || maxLon == 0 { maxLon = event.longitude }
}
let center = CLLocationCoordinate2D(latitude: (minLat + maxLat)/2, longitude: (minLon + maxLon)/2)
let leftTop = CLLocation(latitude: minLat, longitude: minLon)
let rightBottom = CLLocation(latitude: maxLat, longitude: maxLon)
var diagonal = leftTop.distance(from: rightBottom)*1.2
if diagonal < 1000 {
diagonal = 1000
}
let region = MKCoordinateRegion(center: center, latitudinalMeters: diagonal, longitudinalMeters: diagonal)
self.map.setRegion(region, animated: true)
}
@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, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { action, view, completion in
self.deleteEvent(index: indexPath.row, completion: completion)
}
delete.image = UIImage(systemName: "trash")
let edit = UIContextualAction(style: .normal, title: "Edit") { action, view, completion in
self.editEvent(index: indexPath.row)
completion(true)
}
edit.image = UIImage(systemName: "pencil")
edit.backgroundColor = .systemBlue
let configuration = UISwipeActionsConfiguration(actions: [delete, edit])
configuration.performsFirstActionWithFullSwipe = false
return configuration
}
// MARK: - Event actions
func deleteEvent(index: Int, completion: @escaping (Bool) -> Void) {
guard let vehicle = self.vehicle else {
IHProgressHUD.showError(withStatus: "Unknown vehicle")
return
}
let event = vehicle.events[index]
if let eventId = event.id {
IHProgressHUD.show()
Api.remove(event: eventId).observeOn(MainScheduler.instance).subscribe(onSuccess: { vehicle in
completion(self.update(vehicle: vehicle))
}, onError: { error in
completion(false)
IHProgressHUD.show(error: error)
print(error)
}).disposed(by: self.bag)
} else {
self.showAlert(title: "Error", message: "Event ID is not found. Please try to update vehicle record, containing this event.")
}
}
func editEvent(index: Int) {
guard let vehicle = self.vehicle else {
IHProgressHUD.showError(withStatus: "Unknown vehicle")
return
}
let event = vehicle.events[index]
let sb = UIStoryboard(name: "Main", bundle: nil)
let controller = sb.instantiateViewController(identifier: "LocationEditController") as LocationEditController
controller.title = "Edit event"
controller.date = Date(timeIntervalSince1970: event.date)
controller.placemark = Placemark(latitude: event.latitude, longitude: event.longitude, address: event.address)
controller.onDone = { newEvent in
newEvent.id = event.id
self.navigationController?.popViewController(animated: true, completion: {
IHProgressHUD.show()
Api.edit(event: newEvent)
.observeOn(MainScheduler.instance)
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
{ error in
IHProgressHUD.show(error: error)
})
.disposed(by: self.bag)
})
}
self.navigationController?.pushViewController(controller, animated: true)
}
@objc func addEvent(_ sender: UIBarButtonItem) {
guard let vehicle = self.vehicle else {
IHProgressHUD.showError(withStatus: "Unknown vehicle")
return
}
let sb = UIStoryboard(name: "Main", bundle: nil)
let controller = sb.instantiateViewController(identifier: "LocationEditController") as LocationEditController
controller.title = "Add new event"
controller.onDone = { newEvent in
self.navigationController?.popViewController(animated: true, completion: {
IHProgressHUD.show()
Api.add(event: newEvent, to: vehicle.number)
.observeOn(MainScheduler.instance)
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
{ error in
IHProgressHUD.show(error: error)
})
.disposed(by: self.bag)
})
}
self.navigationController?.pushViewController(controller, animated: true)
}
@discardableResult
func update(vehicle: Vehicle) -> Bool {
do {
if let realm = self.vehicle?.realm {
try realm.write {
realm.add(vehicle, update: .all)
}
}
self.vehicle = vehicle
IHProgressHUD.dismiss()
return true
} catch {
IHProgressHUD.show(error: error)
print(error)
return false
}
}
}

View File

@ -0,0 +1,55 @@
import UIKit
import Eureka
import RxSwift
import CoreLocation
class LocationEditController: FormViewController {
private let bag = DisposeBag()
private var doneButton: UIBarButtonItem!
var date = Date()
var placemark: Placemark? = nil
var onDone: ((VehicleEvent) -> Void)?
override func viewDidLoad() {
super.viewDidLoad()
self.doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped(_:)))
self.navigationItem.rightBarButtonItem = self.doneButton
self.doneButton.isEnabled = false
form +++ Section("")
<<< DateTimeInlineRow(){
$0.title = "Date and time"
$0.value = self.date
}.onChange { row in
if let newDate = row.value {
self.date = newDate
}
}
<<< LocationRow() { row in
row.title = "Location"
row.value = self.placemark
}.onChange { row in
if let newPlacemark = row.value {
self.placemark = newPlacemark
self.doneButton.isEnabled = true
} else {
self.doneButton.isEnabled = false
}
}
}
@objc func doneTapped(_ sender: UIBarButtonItem) {
guard let placemark = self.placemark else { return }
let event = VehicleEvent(lat: placemark.latitude, lon: placemark.longitude, speed: -1, dir: -1)
event.date = self.date.timeIntervalSince1970
if let address = placemark.address {
event.address = address
}
self.onDone?(event)
}
}

View File

@ -0,0 +1,156 @@
import Foundation
import MapKit
import Eureka
import RxSwift
import Intents
public struct Placemark: Equatable {
var latitude: Double
var longitude: Double
var address: String?
}
public class LocationPickerController : UIViewController, TypedRowControllerType, MKMapViewDelegate {
public var row: RowOf<Placemark>!
public var onDismissCallback: ((UIViewController) -> ())?
private let bag = DisposeBag()
private var geocodingDisposable: Disposable?
private var address: String?
lazy var mapView : MKMapView = { [unowned self] in
let v = MKMapView(frame: self.view.bounds)
v.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return v
}()
lazy var pinView: UIImageView = { [unowned self] in
let v = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
v.image = UIImage(named: "MapPin", in: Bundle(for: LocationPickerController.self), compatibleWith: nil)
v.image = v.image?.withRenderingMode(.alwaysTemplate)
v.tintColor = self.view.tintColor
v.backgroundColor = .clear
v.clipsToBounds = true
v.contentMode = .scaleAspectFit
v.isUserInteractionEnabled = false
return v
}()
let width: CGFloat = 10.0
let height: CGFloat = 5.0
lazy var ellipse: UIBezierPath = { [unowned self] in
let ellipse = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: self.width, height: self.height))
return ellipse
}()
lazy var ellipsisLayer: CAShapeLayer = { [unowned self] in
let layer = CAShapeLayer()
layer.bounds = CGRect(x: 0, y: 0, width: self.width, height: self.height)
layer.path = self.ellipse.cgPath
layer.fillColor = UIColor.gray.cgColor
layer.fillRule = .nonZero
layer.lineCap = .butt
layer.lineDashPattern = nil
layer.lineDashPhase = 0.0
layer.lineJoin = .miter
layer.lineWidth = 1.0
layer.miterLimit = 10.0
layer.strokeColor = UIColor.gray.cgColor
return layer
}()
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nil, bundle: nil)
}
convenience public init(_ callback: ((UIViewController) -> ())?){
self.init(nibName: nil, bundle: nil)
onDismissCallback = callback
}
public override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(mapView)
mapView.delegate = self
mapView.addSubview(pinView)
mapView.layer.insertSublayer(ellipsisLayer, below: pinView.layer)
let button = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(LocationPickerController.tappedDone(_:)))
button.title = "Done"
navigationItem.rightBarButtonItem = button
if let value = row.value {
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: value.latitude, longitude: value.longitude), latitudinalMeters: 1000, longitudinalMeters: 1000)
mapView.setRegion(region, animated: true)
}
else{
mapView.showsUserLocation = true
}
updateTitle()
}
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let center = mapView.convert(mapView.centerCoordinate, toPointTo: pinView)
pinView.center = CGPoint(x: center.x, y: center.y - (pinView.bounds.height/2))
ellipsisLayer.position = center
}
@objc func tappedDone(_ sender: UIBarButtonItem){
let target = mapView.convert(ellipsisLayer.position, toCoordinateFrom: mapView)
row.value = Placemark(latitude: target.latitude, longitude: target.longitude, address: self.address)
onDismissCallback?(self)
}
func updateTitle(){
let fmt = NumberFormatter()
fmt.maximumFractionDigits = 4
fmt.minimumFractionDigits = 4
let latitude = fmt.string(from: NSNumber(value: mapView.centerCoordinate.latitude))!
let longitude = fmt.string(from: NSNumber(value: mapView.centerCoordinate.longitude))!
title = "\(latitude), \(longitude)"
self.address = nil
self.geocodingDisposable?.dispose()
self.geocodingDisposable = LocationManager
.getAddressForLocation(latitude: mapView.centerCoordinate.latitude, longitude: mapView.centerCoordinate.longitude)
.observeOn(MainScheduler.instance)
.subscribe(onSuccess: { address in
self.title = address
self.address = address
})
}
public func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
ellipsisLayer.transform = CATransform3DMakeScale(0.5, 0.5, 1)
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.pinView.center = CGPoint(x: self!.pinView.center.x, y: self!.pinView.center.y - 10)
})
}
public func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
ellipsisLayer.transform = CATransform3DIdentity
UIView.animate(withDuration: 0.2, animations: { [weak self] in
self?.pinView.center = CGPoint(x: self!.pinView.center.x, y: self!.pinView.center.y + 10)
})
updateTitle()
}
public func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) {
mapView.showsUserLocation = false
let region = MKCoordinateRegion(center: userLocation.coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000)
mapView.setRegion(region, animated: true)
}
}

View File

@ -0,0 +1,57 @@
import UIKit
import Eureka
import CoreLocation
public final class LocationRow: OptionsRow<PushSelectorCell<Placemark>>, PresenterRowType, RowType {
public typealias PresenterRow = LocationPickerController
/// Defines how the view controller will be presented, pushed, etc.
public var presentationMode: PresentationMode<PresenterRow>?
/// Will be called before the presentation occurs.
public var onPresentCallback: ((FormViewController, PresenterRow) -> Void)?
public required init(tag: String?) {
super.init(tag: tag)
presentationMode = .show(controllerProvider: ControllerProvider.callback { return LocationPickerController(){ _ in } }, onDismiss: { vc in _ = vc.navigationController?.popViewController(animated: true) })
displayValueFor = {
guard let placemark = $0 else { return "" }
let fmt = NumberFormatter()
fmt.maximumFractionDigits = 4
fmt.minimumFractionDigits = 4
let latitude = fmt.string(from: NSNumber(value: placemark.latitude))!
let longitude = fmt.string(from: NSNumber(value: placemark.longitude))!
return "\(latitude), \(longitude)"
}
}
/**
Extends `didSelect` method
*/
public override func customDidSelect() {
super.customDidSelect()
guard let presentationMode = presentationMode, !isDisabled else { return }
if let controller = presentationMode.makeController() {
controller.row = self
controller.title = selectorTitle ?? controller.title
onPresentCallback?(cell.formViewController()!, controller)
presentationMode.present(controller, row: self, presentingController: self.cell.formViewController()!)
} else {
presentationMode.present(nil, row: self, presentingController: self.cell.formViewController()!)
}
}
/**
Prepares the pushed row setting its title and completion callback.
*/
public override func prepare(for segue: UIStoryboardSegue) {
super.prepare(for: segue)
guard let rowVC = segue.destination as? PresenterRow else { return }
rowVC.title = selectorTitle ?? rowVC.title
rowVC.onDismissCallback = presentationMode?.onDismissCallback ?? rowVC.onDismissCallback
onPresentCallback?(cell.formViewController()!, rowVC)
rowVC.row = self
}
}

View File

@ -159,7 +159,6 @@ class RecordsController: UIViewController, UITableViewDelegate {
return AudioRecord(path: url.lastPathComponent, number: self.getPlateNumber(from: text), raw: text, duration: duration, event: event)
}
.subscribe(onSuccess: { record in
print(record)
let realm = try? Realm()
try? realm?.write {
realm?.add(record)

View File

@ -274,8 +274,7 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti
}
else if let events = self.vehicle?.events, indexPath.row == ReportGeneralSection.events.rawValue && events.count > 0 {
let controller = sb.instantiateViewController(identifier: "EventsController") as EventsController
controller.events = Array(events)
controller.title = self.vehicle?.number ?? "Events"
controller.vehicle = self.vehicle
self.navigationController?.pushViewController(controller, animated: true)
}
}

View File

@ -0,0 +1,32 @@
import UIKit
extension UINavigationController {
public func pushViewController(
_ viewController: UIViewController,
animated: Bool,
completion: @escaping () -> Void)
{
pushViewController(viewController, animated: animated)
guard animated, let coordinator = transitionCoordinator else {
DispatchQueue.main.async { completion() }
return
}
coordinator.animate(alongsideTransition: nil) { _ in completion() }
}
func popViewController(
animated: Bool,
completion: @escaping () -> Void)
{
popViewController(animated: animated)
guard animated, let coordinator = transitionCoordinator else {
DispatchQueue.main.async { completion() }
return
}
coordinator.animate(alongsideTransition: nil) { _ in completion() }
}
}

View File

@ -1,8 +1,10 @@
import Foundation
import RealmSwift
import RxSwift
import CoreLocation
class VehicleEvent: Object, Codable {
public class VehicleEvent: Object, Codable {
@objc dynamic var id: String?
@objc dynamic var date: TimeInterval = Date().timeIntervalSince1970
@objc dynamic var latitude: Double = 0
@objc dynamic var longitude: Double = 0
@ -10,6 +12,10 @@ class VehicleEvent: Object, Codable {
@objc dynamic var direction: Double = 0
@objc dynamic var address: String? = nil
var coordinate: CLLocationCoordinate2D {
return CLLocationCoordinate2D(latitude: self.latitude, longitude: self.longitude)
}
init(lat: Double, lon: Double, speed: Double, dir: Double) {
self.latitude = lat
self.longitude = lon

View File

@ -40,14 +40,14 @@ class Api {
}
return URLSession.shared.rx.data(request: request).asSingle().map { data in
let str = String(data: data, encoding: .utf8)
print("================================")
if let string = str?.replacingOccurrences(of: "\\\"", with: "\"")
.replacingOccurrences(of: "\\'", with: "'")
.replacingOccurrences(of: "\\n", with: "") {
print(string)
}
print("================================")
// let str = String(data: data, encoding: .utf8)
// print("================================")
// if let string = str?.replacingOccurrences(of: "\\\"", with: "\"")
// .replacingOccurrences(of: "\\'", with: "'")
// .replacingOccurrences(of: "\\n", with: "") {
// print(string)
// }
// print("================================")
let resp = try JSONDecoder().decode(Response<T>.self, from: data)
if resp.success {
return resp.data!
@ -231,4 +231,14 @@ class Api {
return vehicle
}
}
public static func remove(event id: String) -> Single<Vehicle> {
let body = ["eventId": id]
return self.makeBodyRequest(api: "events", body: body, method: "DELETE")
}
public static func edit(event: VehicleEvent) -> Single<Vehicle> {
let body = ["event": event]
return self.makeBodyRequest(api: "events", body: body, method: "PUT")
}
}

View File

@ -106,12 +106,7 @@ class LocationManager {
}
static func requestCurrentLocation() -> Single<VehicleEvent> {
return self.checkPermissions().flatMap(self.requestLocation).do(onSuccess: { event in
print("Get location success")
}, onSubscribed: {
print("Get location subscribed")
}, onDispose: {
print("Get location dispose")
return self.checkPermissions().flatMap(self.requestLocation).do(onDispose: {
self.manager.stopUpdatingLocation()
})
}

View File

@ -105,7 +105,7 @@ class Recorder {
if let transcription = result?.bestTranscription {
self.result = transcription.formattedString
self.endRecognitionTimer?.invalidate()
self.endRecognitionTimer = Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { timer in
self.endRecognitionTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
self.finishRecording()
observer(.success(self.result))
}