Compare commits
No commits in common. "771b5923b61ecb72cc9176628d9bb6c054f82b00" and "df43b9ff7fd9a1a4319b1d14e1110ee0f28a245a" have entirely different histories.
771b5923b6
...
df43b9ff7f
@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 52;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@ -25,15 +25,6 @@
|
|||||||
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471523FDEB2A00B424AF /* MainSplitController.swift */; };
|
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471523FDEB2A00B424AF /* MainSplitController.swift */; };
|
||||||
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471723FDEBFA00B424AF /* ReportController.swift */; };
|
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471723FDEBFA00B424AF /* ReportController.swift */; };
|
||||||
7A11471A23FE839000B424AF /* AuthController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471923FE839000B424AF /* AuthController.swift */; };
|
7A11471A23FE839000B424AF /* AuthController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471923FE839000B424AF /* AuthController.swift */; };
|
||||||
7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE492A2E820300626A6E /* UIStackView.swift */; };
|
|
||||||
7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */; };
|
|
||||||
7A1CF80329A41C62007962DA /* Realm in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80229A41C62007962DA /* Realm */; };
|
|
||||||
7A1CF80529A41C66007962DA /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80429A41C66007962DA /* RealmSwift */; };
|
|
||||||
7A1CF80829A41D58007962DA /* RxBlocking in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80729A41D58007962DA /* RxBlocking */; };
|
|
||||||
7A1CF80A29A41D58007962DA /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80929A41D58007962DA /* RxCocoa */; };
|
|
||||||
7A1CF80C29A41D58007962DA /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80B29A41D58007962DA /* RxRelay */; };
|
|
||||||
7A1CF80E29A41D58007962DA /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7A1CF80D29A41D58007962DA /* RxSwift */; };
|
|
||||||
7A1CF81629A42117007962DA /* Realm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1CF81529A42117007962DA /* Realm.swift */; };
|
|
||||||
7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */; };
|
7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */; };
|
||||||
7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A21112924FC3D7E003BBF6F /* AudioEngine.swift */; };
|
7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A21112924FC3D7E003BBF6F /* AudioEngine.swift */; };
|
||||||
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADC6249D43210035F39E /* RegionsController.swift */; };
|
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADC6249D43210035F39E /* RegionsController.swift */; };
|
||||||
@ -85,6 +76,9 @@
|
|||||||
7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A96AE2E246B2BCD00297C33 /* WebKit.framework */; };
|
7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A96AE2E246B2BCD00297C33 /* WebKit.framework */; };
|
||||||
7A99406426E4BFAE002E9CB6 /* VehicleNoteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A99406326E4BFAE002E9CB6 /* VehicleNoteCell.swift */; };
|
7A99406426E4BFAE002E9CB6 /* VehicleNoteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A99406326E4BFAE002E9CB6 /* VehicleNoteCell.swift */; };
|
||||||
7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FEEC72529AB23001CA50E /* RxRealmDataSource.swift */; };
|
7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A9FEEC72529AB23001CA50E /* RxRealmDataSource.swift */; };
|
||||||
|
7AA54C1C26CD977A00F2BF28 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 7AA54C1B26CD977A00F2BF28 /* RxCocoa */; };
|
||||||
|
7AA54C1E26CD977A00F2BF28 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7AA54C1D26CD977A00F2BF28 /* RxSwift */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||||
|
7AA54C2026CD977A00F2BF28 /* RxRealm in Frameworks */ = {isa = PBXBuildFile; productRef = 7AA54C1F26CD977A00F2BF28 /* RxRealm */; };
|
||||||
7AA7BC3325A5DFB80053A5D5 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF58D332402A91C00CE01A0 /* Kingfisher */; };
|
7AA7BC3325A5DFB80053A5D5 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF58D332402A91C00CE01A0 /* Kingfisher */; };
|
||||||
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */; };
|
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */; };
|
||||||
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABDE1C2532F3EB0041AFC6 /* PKHUD */; };
|
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABDE1C2532F3EB0041AFC6 /* PKHUD */; };
|
||||||
@ -134,6 +128,8 @@
|
|||||||
7AF6D21F2677C1680086EA64 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474823FF2B2D00B424AF /* Response.swift */; };
|
7AF6D21F2677C1680086EA64 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474823FF2B2D00B424AF /* Response.swift */; };
|
||||||
7AF6D2202677C1680086EA64 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A333813249A532400D878F1 /* Filter.swift */; };
|
7AF6D2202677C1680086EA64 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A333813249A532400D878F1 /* Filter.swift */; };
|
||||||
7AF6D2212677C1680086EA64 /* PagedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6841A913FABBB0AB20DEF4FC /* PagedResponse.swift */; };
|
7AF6D2212677C1680086EA64 /* PagedResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6841A913FABBB0AB20DEF4FC /* PagedResponse.swift */; };
|
||||||
|
7AF6D2232677C2B40086EA64 /* Realm in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF6D2222677C2B40086EA64 /* Realm */; };
|
||||||
|
7AF6D2252677C2B40086EA64 /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF6D2242677C2B40086EA64 /* RealmSwift */; };
|
||||||
7AF6D2282677C2DC0086EA64 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE30246B2FE400297C33 /* Constants.swift */; };
|
7AF6D2282677C2DC0086EA64 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE30246B2FE400297C33 /* Constants.swift */; };
|
||||||
7AF6D22A2677C3AD0086EA64 /* Exportable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE8424D26109F78002F6B31 /* Exportable.swift */; };
|
7AF6D22A2677C3AD0086EA64 /* Exportable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE8424D26109F78002F6B31 /* Exportable.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
@ -200,9 +196,6 @@
|
|||||||
7A11474A23FF368B00B424AF /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
|
7A11474A23FF368B00B424AF /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
|
||||||
7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = "<group>"; };
|
7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = "<group>"; };
|
||||||
7A15051124DB3E3000F39631 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; };
|
7A15051124DB3E3000F39631 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = "<group>"; };
|
||||||
7A17CE492A2E820300626A6E /* UIStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackView.swift; sourceTree = "<group>"; };
|
|
||||||
7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UISegmentedControl.swift; sourceTree = "<group>"; };
|
|
||||||
7A1CF81529A42117007962DA /* Realm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Realm.swift; sourceTree = "<group>"; };
|
|
||||||
7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockBarButtonItem.swift; sourceTree = "<group>"; };
|
7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockBarButtonItem.swift; sourceTree = "<group>"; };
|
||||||
7A21112924FC3D7E003BBF6F /* AudioEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = "<group>"; };
|
7A21112924FC3D7E003BBF6F /* AudioEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = "<group>"; };
|
||||||
7A27ADC6249D43210035F39E /* RegionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsController.swift; sourceTree = "<group>"; };
|
7A27ADC6249D43210035F39E /* RegionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsController.swift; sourceTree = "<group>"; };
|
||||||
@ -330,13 +323,12 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
7A1CF80C29A41D58007962DA /* RxRelay in Frameworks */,
|
7AA54C1E26CD977A00F2BF28 /* RxSwift in Frameworks */,
|
||||||
7A1CF80529A41C66007962DA /* RealmSwift in Frameworks */,
|
7AF6D2252677C2B40086EA64 /* RealmSwift in Frameworks */,
|
||||||
7A1CF80829A41D58007962DA /* RxBlocking in Frameworks */,
|
7AA54C1C26CD977A00F2BF28 /* RxCocoa in Frameworks */,
|
||||||
7A1CF80A29A41D58007962DA /* RxCocoa in Frameworks */,
|
7AF6D2232677C2B40086EA64 /* Realm in Frameworks */,
|
||||||
7A1CF80329A41C62007962DA /* Realm in Frameworks */,
|
|
||||||
7AABB1F2267E9CC800D7AB32 /* SwiftDate in Frameworks */,
|
7AABB1F2267E9CC800D7AB32 /* SwiftDate in Frameworks */,
|
||||||
7A1CF80E29A41D58007962DA /* RxSwift in Frameworks */,
|
7AA54C2026CD977A00F2BF28 /* RxRealm in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -615,8 +607,6 @@
|
|||||||
7AC355582969746600889457 /* UIControl.swift */,
|
7AC355582969746600889457 /* UIControl.swift */,
|
||||||
7AC3555A296995B200889457 /* UIEdgeInsets.swift */,
|
7AC3555A296995B200889457 /* UIEdgeInsets.swift */,
|
||||||
7A91894E29A2BD8700519C74 /* GestureRecognizers.swift */,
|
7A91894E29A2BD8700519C74 /* GestureRecognizers.swift */,
|
||||||
7A17CE492A2E820300626A6E /* UIStackView.swift */,
|
|
||||||
7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */,
|
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -669,7 +659,6 @@
|
|||||||
children = (
|
children = (
|
||||||
7A27ADF824A09CAD0035F39E /* CocoaError.swift */,
|
7A27ADF824A09CAD0035F39E /* CocoaError.swift */,
|
||||||
7AE8424D26109F78002F6B31 /* Exportable.swift */,
|
7AE8424D26109F78002F6B31 /* Exportable.swift */,
|
||||||
7A1CF81529A42117007962DA /* Realm.swift */,
|
|
||||||
);
|
);
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -746,13 +735,12 @@
|
|||||||
);
|
);
|
||||||
name = AutoCatCore;
|
name = AutoCatCore;
|
||||||
packageProductDependencies = (
|
packageProductDependencies = (
|
||||||
|
7AF6D2222677C2B40086EA64 /* Realm */,
|
||||||
|
7AF6D2242677C2B40086EA64 /* RealmSwift */,
|
||||||
7AABB1F1267E9CC800D7AB32 /* SwiftDate */,
|
7AABB1F1267E9CC800D7AB32 /* SwiftDate */,
|
||||||
7A1CF80229A41C62007962DA /* Realm */,
|
7AA54C1B26CD977A00F2BF28 /* RxCocoa */,
|
||||||
7A1CF80429A41C66007962DA /* RealmSwift */,
|
7AA54C1D26CD977A00F2BF28 /* RxSwift */,
|
||||||
7A1CF80729A41D58007962DA /* RxBlocking */,
|
7AA54C1F26CD977A00F2BF28 /* RxRealm */,
|
||||||
7A1CF80929A41D58007962DA /* RxCocoa */,
|
|
||||||
7A1CF80B29A41D58007962DA /* RxRelay */,
|
|
||||||
7A1CF80D29A41D58007962DA /* RxSwift */,
|
|
||||||
);
|
);
|
||||||
productName = AutoCatCore;
|
productName = AutoCatCore;
|
||||||
productReference = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */;
|
productReference = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */;
|
||||||
@ -791,14 +779,15 @@
|
|||||||
);
|
);
|
||||||
mainGroup = 7A1146F423FDE7E500B424AF;
|
mainGroup = 7A1146F423FDE7E500B424AF;
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
|
7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */,
|
||||||
|
7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */,
|
||||||
|
7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */,
|
||||||
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||||
7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */,
|
7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */,
|
||||||
7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */,
|
7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */,
|
||||||
7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */,
|
7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */,
|
||||||
7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */,
|
7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */,
|
||||||
7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */,
|
7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */,
|
||||||
7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */,
|
|
||||||
7A1CF80629A41D58007962DA /* XCRemoteSwiftPackageReference "RxSwift" */,
|
|
||||||
);
|
);
|
||||||
productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */;
|
productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
@ -871,7 +860,6 @@
|
|||||||
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */,
|
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */,
|
||||||
7A0420B62568650C00034941 /* DkbmController.swift in Sources */,
|
7A0420B62568650C00034941 /* DkbmController.swift in Sources */,
|
||||||
7A27ADF5249FD2F90035F39E /* FileManagerExt.swift in Sources */,
|
7A27ADF5249FD2F90035F39E /* FileManagerExt.swift in Sources */,
|
||||||
7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */,
|
|
||||||
7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */,
|
7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */,
|
||||||
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */,
|
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */,
|
||||||
7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */,
|
7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */,
|
||||||
@ -923,7 +911,6 @@
|
|||||||
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
|
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
|
||||||
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
|
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
|
||||||
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
|
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
|
||||||
7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */,
|
|
||||||
6841A85D4B60DB71D1E68DA0 /* ImageGrid.swift in Sources */,
|
6841A85D4B60DB71D1E68DA0 /* ImageGrid.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@ -960,7 +947,6 @@
|
|||||||
7A0B663729984201006F5189 /* DateCache.swift in Sources */,
|
7A0B663729984201006F5189 /* DateCache.swift in Sources */,
|
||||||
7AF6D21D2677C1680086EA64 /* Osago.swift in Sources */,
|
7AF6D21D2677C1680086EA64 /* Osago.swift in Sources */,
|
||||||
7AF6D2152677C1680086EA64 /* Settings.swift in Sources */,
|
7AF6D2152677C1680086EA64 /* Settings.swift in Sources */,
|
||||||
7A1CF81629A42117007962DA /* Realm.swift in Sources */,
|
|
||||||
7A761C052677F1BC0005F28F /* CocoaError.swift in Sources */,
|
7A761C052677F1BC0005F28F /* CocoaError.swift in Sources */,
|
||||||
7AF6D2132677C15A0086EA64 /* AudioRecord.swift in Sources */,
|
7AF6D2132677C15A0086EA64 /* AudioRecord.swift in Sources */,
|
||||||
7AF6D21B2677C1680086EA64 /* Vehicle.swift in Sources */,
|
7AF6D21B2677C1680086EA64 /* Vehicle.swift in Sources */,
|
||||||
@ -1158,18 +1144,15 @@
|
|||||||
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 = 117;
|
CURRENT_PROJECT_VERSION = 111;
|
||||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.0;
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat;
|
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
@ -1186,18 +1169,15 @@
|
|||||||
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 = 117;
|
CURRENT_PROJECT_VERSION = 111;
|
||||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.0;
|
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0;
|
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat;
|
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SUPPORTS_MACCATALYST = YES;
|
SUPPORTS_MACCATALYST = YES;
|
||||||
@ -1357,20 +1337,20 @@
|
|||||||
minimumVersion = 6.1.0;
|
minimumVersion = 6.1.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */ = {
|
7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
|
||||||
repositoryURL = "https://github.com/realm/realm-swift.git";
|
|
||||||
requirement = {
|
|
||||||
kind = upToNextMajorVersion;
|
|
||||||
minimumVersion = 10.36.0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
7A1CF80629A41D58007962DA /* XCRemoteSwiftPackageReference "RxSwift" */ = {
|
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/ReactiveX/RxSwift.git";
|
repositoryURL = "https://github.com/ReactiveX/RxSwift.git";
|
||||||
requirement = {
|
requirement = {
|
||||||
kind = upToNextMajorVersion;
|
kind = upToNextMajorVersion;
|
||||||
minimumVersion = 6.0.0;
|
minimumVersion = 5.0.1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/realm/realm-cocoa";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 5.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */ = {
|
7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */ = {
|
||||||
@ -1381,6 +1361,14 @@
|
|||||||
minimumVersion = 5.0.0;
|
minimumVersion = 5.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/RxSwiftCommunity/RxRealm";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 3.0.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */ = {
|
7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/sindresorhus/ExceptionCatcher";
|
repositoryURL = "https://github.com/sindresorhus/ExceptionCatcher";
|
||||||
@ -1416,36 +1404,6 @@
|
|||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
7A1CF80229A41C62007962DA /* Realm */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */;
|
|
||||||
productName = Realm;
|
|
||||||
};
|
|
||||||
7A1CF80429A41C66007962DA /* RealmSwift */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = 7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */;
|
|
||||||
productName = RealmSwift;
|
|
||||||
};
|
|
||||||
7A1CF80729A41D58007962DA /* RxBlocking */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = 7A1CF80629A41D58007962DA /* XCRemoteSwiftPackageReference "RxSwift" */;
|
|
||||||
productName = RxBlocking;
|
|
||||||
};
|
|
||||||
7A1CF80929A41D58007962DA /* RxCocoa */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = 7A1CF80629A41D58007962DA /* XCRemoteSwiftPackageReference "RxSwift" */;
|
|
||||||
productName = RxCocoa;
|
|
||||||
};
|
|
||||||
7A1CF80B29A41D58007962DA /* RxRelay */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = 7A1CF80629A41D58007962DA /* XCRemoteSwiftPackageReference "RxSwift" */;
|
|
||||||
productName = RxRelay;
|
|
||||||
};
|
|
||||||
7A1CF80D29A41D58007962DA /* RxSwift */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = 7A1CF80629A41D58007962DA /* XCRemoteSwiftPackageReference "RxSwift" */;
|
|
||||||
productName = RxSwift;
|
|
||||||
};
|
|
||||||
7A35177A27E23F8800DC538C /* Eureka */ = {
|
7A35177A27E23F8800DC538C /* Eureka */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */;
|
package = 7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */;
|
||||||
@ -1456,6 +1414,21 @@
|
|||||||
package = 7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */;
|
package = 7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */;
|
||||||
productName = ExceptionCatcher;
|
productName = ExceptionCatcher;
|
||||||
};
|
};
|
||||||
|
7AA54C1B26CD977A00F2BF28 /* RxCocoa */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */;
|
||||||
|
productName = RxCocoa;
|
||||||
|
};
|
||||||
|
7AA54C1D26CD977A00F2BF28 /* RxSwift */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */;
|
||||||
|
productName = RxSwift;
|
||||||
|
};
|
||||||
|
7AA54C1F26CD977A00F2BF28 /* RxRealm */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */;
|
||||||
|
productName = RxRealm;
|
||||||
|
};
|
||||||
7AABB1F1267E9CC800D7AB32 /* SwiftDate */ = {
|
7AABB1F1267E9CC800D7AB32 /* SwiftDate */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */;
|
package = 7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */;
|
||||||
@ -1476,6 +1449,16 @@
|
|||||||
package = 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
package = 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */;
|
||||||
productName = Kingfisher;
|
productName = Kingfisher;
|
||||||
};
|
};
|
||||||
|
7AF6D2222677C2B40086EA64 /* Realm */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */;
|
||||||
|
productName = Realm;
|
||||||
|
};
|
||||||
|
7AF6D2242677C2B40086EA64 /* RealmSwift */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */;
|
||||||
|
productName = RealmSwift;
|
||||||
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = 7A1146F523FDE7E500B424AF /* Project object */;
|
rootObject = 7A1146F523FDE7E500B424AF /* Project object */;
|
||||||
|
|||||||
@ -37,21 +37,30 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"identity" : "realm-core",
|
"identity" : "realm-cocoa",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/realm/realm-core.git",
|
"location" : "https://github.com/realm/realm-cocoa",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "dd91f5f967c4ae89c37e24ab2a0315c31106648f",
|
"revision" : "2dce752b48c3265c63ab04a8c66ddfdf9185f847",
|
||||||
"version" : "13.6.0"
|
"version" : "5.5.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"identity" : "realm-swift",
|
"identity" : "realm-core",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/realm/realm-swift.git",
|
"location" : "https://github.com/realm/realm-core",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "8ac6fe1aa5d0fb0100062d80863416a4d70de8ca",
|
"revision" : "66d79b3c5213fb14d491c1b22193077b488d49a6",
|
||||||
"version" : "10.37.0"
|
"version" : "6.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "rxrealm",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/RxSwiftCommunity/RxRealm",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "4dcae40562b5a086dd4711fa8a596be0436dc474",
|
||||||
|
"version" : "3.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -59,8 +68,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/ReactiveX/RxSwift.git",
|
"location" : "https://github.com/ReactiveX/RxSwift.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "b4307ba0b6425c0ba4178e138799946c3da594f8",
|
"revision" : "254617dd7fae0c45319ba5fbea435bf4d0e15b5d",
|
||||||
"version" : "6.5.0"
|
"version" : "5.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
BreakpointExtensionID = "Xcode.Breakpoint.SymbolicBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.SymbolicBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
uuid = "676638C8-1CC5-4C04-98B0-1C0D6CB28B76"
|
uuid = "676638C8-1CC5-4C04-98B0-1C0D6CB28B76"
|
||||||
shouldBeEnabled = "No"
|
shouldBeEnabled = "Yes"
|
||||||
ignoreCount = "0"
|
ignoreCount = "0"
|
||||||
continueAfterRunningActions = "No"
|
continueAfterRunningActions = "No"
|
||||||
symbolName = "UITableViewAlertForLayoutOutsideViewHierarchy"
|
symbolName = "UITableViewAlertForLayoutOutsideViewHierarchy"
|
||||||
@ -27,68 +27,5 @@
|
|||||||
</Locations>
|
</Locations>
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</BreakpointProxy>
|
||||||
<BreakpointProxy
|
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
|
||||||
<BreakpointContent
|
|
||||||
uuid = "2786565A-9610-4232-920E-0763816C4DBF"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
filePath = "../../../Library/Developer/Xcode/DerivedData/AutoCat-fhilwnlnsrpirleiajogdcyhyyey/SourcePackages/checkouts/Eureka/Source/Rows/DateInlineRow.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "37"
|
|
||||||
endingLineNumber = "37"
|
|
||||||
landmarkName = "configurePickerStyle(_:_:)"
|
|
||||||
landmarkType = "7">
|
|
||||||
<Locations>
|
|
||||||
<Location
|
|
||||||
uuid = "2786565A-9610-4232-920E-0763816C4DBF - f20dc4504decd67d"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
symbolName = "Eureka.DatePickerRowProtocol.configurePickerStyle(Eureka.DatePickerCell, __C.UIDatePickerMode) -> ()"
|
|
||||||
moduleName = "AutoCat"
|
|
||||||
usesParentBreakpointCondition = "Yes"
|
|
||||||
urlString = "file:///Users/selim/Library/Developer/Xcode/DerivedData/AutoCat-fhilwnlnsrpirleiajogdcyhyyey/SourcePackages/checkouts/Eureka/Source/Rows/DateInlineRow.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "37"
|
|
||||||
endingLineNumber = "37"
|
|
||||||
offsetFromSymbolStart = "260">
|
|
||||||
</Location>
|
|
||||||
<Location
|
|
||||||
uuid = "2786565A-9610-4232-920E-0763816C4DBF - f20dc4504decd67d"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
symbolName = "Eureka.DatePickerRowProtocol.configurePickerStyle(Eureka.DatePickerCell, __C.UIDatePickerMode) -> ()"
|
|
||||||
moduleName = "AutoCat"
|
|
||||||
usesParentBreakpointCondition = "Yes"
|
|
||||||
urlString = "file:///Users/selim/Library/Developer/Xcode/DerivedData/AutoCat-fhilwnlnsrpirleiajogdcyhyyey/SourcePackages/checkouts/Eureka/Source/Rows/DateInlineRow.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "37"
|
|
||||||
endingLineNumber = "37"
|
|
||||||
offsetFromSymbolStart = "256">
|
|
||||||
</Location>
|
|
||||||
<Location
|
|
||||||
uuid = "2786565A-9610-4232-920E-0763816C4DBF - f20dc4504decd67d"
|
|
||||||
shouldBeEnabled = "Yes"
|
|
||||||
ignoreCount = "0"
|
|
||||||
continueAfterRunningActions = "No"
|
|
||||||
symbolName = "Eureka.DatePickerRowProtocol.configurePickerStyle(Eureka.DatePickerCell, __C.UIDatePickerMode) -> ()"
|
|
||||||
moduleName = "AutoCat"
|
|
||||||
usesParentBreakpointCondition = "Yes"
|
|
||||||
urlString = "file:///Users/selim/Library/Developer/Xcode/DerivedData/AutoCat-fhilwnlnsrpirleiajogdcyhyyey/SourcePackages/checkouts/Eureka/Source/Rows/DateInlineRow.swift"
|
|
||||||
startingColumnNumber = "9223372036854775807"
|
|
||||||
endingColumnNumber = "9223372036854775807"
|
|
||||||
startingLineNumber = "37"
|
|
||||||
endingLineNumber = "37"
|
|
||||||
offsetFromSymbolStart = "112">
|
|
||||||
</Location>
|
|
||||||
</Locations>
|
|
||||||
</BreakpointContent>
|
|
||||||
</BreakpointProxy>
|
|
||||||
</Breakpoints>
|
</Breakpoints>
|
||||||
</Bucket>
|
</Bucket>
|
||||||
|
|||||||
@ -15,13 +15,6 @@ extension UISearchController {
|
|||||||
searchController.obscuresBackgroundDuringPresentation = false
|
searchController.obscuresBackgroundDuringPresentation = false
|
||||||
searchController.hidesNavigationBarDuringPresentation = false
|
searchController.hidesNavigationBarDuringPresentation = false
|
||||||
searchController.searchBar.keyboardType = .webSearch
|
searchController.searchBar.keyboardType = .webSearch
|
||||||
|
|
||||||
if #available(iOS 16, *) {
|
|
||||||
searchController.scopeBarActivation = .onTextEntry
|
|
||||||
} else {
|
|
||||||
searchController.automaticallyShowsScopeBar = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return searchController
|
return searchController
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,14 +37,4 @@ extension UISearchController {
|
|||||||
searchBar.smartInsertDeleteType = .no
|
searchBar.smartInsertDeleteType = .no
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
func scopeButtons(_ buttons: [String]) -> UISearchController {
|
|
||||||
searchBar.scopeButtonTitles = buttons
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
func searchBarDelegate(_ delegate: UISearchBarDelegate) -> UISearchController {
|
|
||||||
searchBar.delegate = delegate
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,42 +0,0 @@
|
|||||||
//
|
|
||||||
// UISegmentedControl.swift
|
|
||||||
// AutoCat
|
|
||||||
//
|
|
||||||
// Created by Selim Mustafaev on 06.06.2023.
|
|
||||||
// Copyright © 2023 Selim Mustafaev. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
extension UISegmentedControl {
|
|
||||||
|
|
||||||
static func segments(titles: [String]) -> UISegmentedControl {
|
|
||||||
let view = UISegmentedControl(items: titles)
|
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
static func segments(images: [UIImage?]) -> UISegmentedControl {
|
|
||||||
let view = UISegmentedControl(items: images.compactMap { $0 })
|
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
return view
|
|
||||||
}
|
|
||||||
|
|
||||||
func onValueChanged(_ closure: @escaping (Int) -> Void) -> UISegmentedControl {
|
|
||||||
addActionImpl(for: .valueChanged) { [weak self] in
|
|
||||||
guard let index = self?.selectedSegmentIndex else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
closure(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
func select(index: Int) -> UISegmentedControl {
|
|
||||||
selectedSegmentIndex = index
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
//
|
|
||||||
// UIStackView.swift
|
|
||||||
// AutoCat
|
|
||||||
//
|
|
||||||
// Created by Selim Mustafaev on 05.06.2023.
|
|
||||||
// Copyright © 2023 Selim Mustafaev. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
|
|
||||||
extension UIStackView {
|
|
||||||
|
|
||||||
static func horizontal(_ views: [UIView]) -> UIStackView {
|
|
||||||
let stack = UIStackView(arrangedSubviews: views)
|
|
||||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
stack.axis = .horizontal
|
|
||||||
stack.spacing = 16
|
|
||||||
return stack
|
|
||||||
}
|
|
||||||
|
|
||||||
static func vertical(_ views: [UIView]) -> UIStackView {
|
|
||||||
let stack = UIStackView(arrangedSubviews: views)
|
|
||||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
stack.axis = .vertical
|
|
||||||
stack.spacing = 16
|
|
||||||
return stack
|
|
||||||
}
|
|
||||||
|
|
||||||
func spacing(_ spacing: CGFloat) -> UIStackView {
|
|
||||||
self.spacing = spacing
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
func alignment(_ alignment: Alignment) -> UIStackView {
|
|
||||||
self.alignment = alignment
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
func distribution(_ distribution: Distribution) -> UIStackView {
|
|
||||||
self.distribution = distribution
|
|
||||||
return self
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeAllArrangedSubviews() {
|
|
||||||
arrangedSubviews.forEach {
|
|
||||||
self.removeArrangedSubview($0)
|
|
||||||
NSLayoutConstraint.deactivate($0.constraints)
|
|
||||||
$0.removeFromSuperview()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func addArrangedSubviews(_ views: [UIView]) {
|
|
||||||
views.forEach { addArrangedSubview($0) }
|
|
||||||
}
|
|
||||||
|
|
||||||
func setArrangedSubviews(_ views: [UIView]) {
|
|
||||||
removeAllArrangedSubviews()
|
|
||||||
addArrangedSubviews(views)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -26,8 +26,92 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||||
|
|
||||||
let config = Realm.Configuration(
|
let config = Realm.Configuration(
|
||||||
schemaVersion: 40,
|
schemaVersion: 38,
|
||||||
migrationBlock: { migration, oldSchemaVersion in
|
migrationBlock: { migration, oldSchemaVersion in
|
||||||
|
if oldSchemaVersion <= 3 {
|
||||||
|
var numbers: [String] = []
|
||||||
|
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||||
|
if let number = old?["number"] as? String {
|
||||||
|
if numbers.contains(number) {
|
||||||
|
migration.delete(old!)
|
||||||
|
} else {
|
||||||
|
numbers.append(number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldSchemaVersion <= 14 {
|
||||||
|
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||||
|
new!["isRightWheel"] = RealmOptional<Bool>(old!["isRightWheel"] as? Bool)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldSchemaVersion <= 18 {
|
||||||
|
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||||
|
let addedDate = old!["addedDate"] as! TimeInterval
|
||||||
|
let events = old!.dynamicList("events")
|
||||||
|
new!["addedDate"] = addedDate/1000
|
||||||
|
|
||||||
|
let lastEvent = events.max { first, second in
|
||||||
|
let firstDate = first["date"] as! TimeInterval
|
||||||
|
let secondDate = second["date"] as! TimeInterval
|
||||||
|
return firstDate < secondDate
|
||||||
|
}
|
||||||
|
|
||||||
|
if let lastEvent = lastEvent {
|
||||||
|
new!["updatedDate"] = max(addedDate/1000, lastEvent["date"] as! TimeInterval)
|
||||||
|
} else {
|
||||||
|
new!["updatedDate"] = addedDate/1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldSchemaVersion == 19 || oldSchemaVersion == 20 {
|
||||||
|
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||||
|
guard let addedDate = old?["addedDate"] as? TimeInterval else { return }
|
||||||
|
guard let updatedDate = old?["updatedDate"] as? TimeInterval else { return }
|
||||||
|
|
||||||
|
if addedDate > TimeInterval(Int32.max) {
|
||||||
|
new!["addedDate"] = addedDate/1000
|
||||||
|
}
|
||||||
|
|
||||||
|
if updatedDate > TimeInterval(Int32.max) {
|
||||||
|
new!["updatedDate"] = updatedDate/1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldSchemaVersion <= 21 {
|
||||||
|
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||||
|
if let oldEngineVolume = (old?["engine"] as? MigrationObject)?["volume"] as? Int {
|
||||||
|
(new?["engine"] as? MigrationObject)?["volume"] = RealmOptional(oldEngineVolume)
|
||||||
|
} else {
|
||||||
|
(new?["engine"] as? MigrationObject)?["volume"] = RealmOptional(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldSchemaVersion <= 22 {
|
||||||
|
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||||
|
if let oldEnginePower = (old?["engine"] as? MigrationObject)?["powerKw"] as? Int {
|
||||||
|
(new?["engine"] as? MigrationObject)?["powerKw"] = RealmOptional(oldEnginePower)
|
||||||
|
} else {
|
||||||
|
(new?["engine"] as? MigrationObject)?["powerKw"] = RealmOptional(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldSchemaVersion <= 23 {
|
||||||
|
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||||
|
if let oldJapanese = old?["isJapanese"] as? Bool {
|
||||||
|
new?["isJapanese"] = RealmOptional(oldJapanese)
|
||||||
|
} else {
|
||||||
|
new?["isJapanese"] = RealmOptional<Bool>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if oldSchemaVersion <= 31 {
|
if oldSchemaVersion <= 31 {
|
||||||
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||||
if let oldDebugInfo = old?["debugInfo"] as? DynamicObject, let newDebugInfo = new?["debugInfo"] as? DynamicObject {
|
if let oldDebugInfo = old?["debugInfo"] as? DynamicObject, let newDebugInfo = new?["debugInfo"] as? DynamicObject {
|
||||||
|
|||||||
@ -173,17 +173,17 @@
|
|||||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
<prototypes>
|
<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">
|
<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="432"/>
|
<rect key="frame" x="0.0" y="50" width="375" height="431.5"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QIb-Hv-tvk" id="Ypt-ch-fGT">
|
<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="432"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="431.5"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HP8-oO-yhP">
|
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HP8-oO-yhP">
|
||||||
<rect key="frame" x="16" y="8" width="343" height="416"/>
|
<rect key="frame" x="16" y="8" width="343" height="415.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="k4Z-KM-byE">
|
<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="416"/>
|
<rect key="frame" x="0.0" y="0.0" width="335" height="415.5"/>
|
||||||
<subviews>
|
<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">
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="335" height="201"/>
|
||||||
@ -192,7 +192,7 @@
|
|||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</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">
|
<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="207"/>
|
<rect key="frame" x="0.0" y="209" width="335" height="206.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
||||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@ -200,7 +200,7 @@
|
|||||||
</subviews>
|
</subviews>
|
||||||
</stackView>
|
</stackView>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="750" verticalHuggingPriority="251" image="person" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="CFI-xa-eLs">
|
<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.5" width="0.0" height="413.5"/>
|
<rect key="frame" x="343" y="1.5" width="0.0" height="413"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
</stackView>
|
</stackView>
|
||||||
|
|||||||
@ -65,7 +65,7 @@ class AuthController: UIViewController, ASAuthorizationControllerDelegate, ASAut
|
|||||||
authorizationController.performRequests()
|
authorizationController.performRequests()
|
||||||
}
|
}
|
||||||
|
|
||||||
func goToMainScreen(user: AutoCatCore.User) {
|
func goToMainScreen(user: User) {
|
||||||
guard let realm = try? Realm() else {
|
guard let realm = try? Realm() else {
|
||||||
HUD.flash(.labeledError(title: nil, subtitle: "Database error"))
|
HUD.flash(.labeledError(title: nil, subtitle: "Database error"))
|
||||||
return
|
return
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import UIKit
|
|||||||
import RealmSwift
|
import RealmSwift
|
||||||
import RxSwift
|
import RxSwift
|
||||||
import SwiftDate
|
import SwiftDate
|
||||||
|
import RxRealm
|
||||||
import PKHUD
|
import PKHUD
|
||||||
import CoreLocation
|
import CoreLocation
|
||||||
import AutoCatCore
|
import AutoCatCore
|
||||||
@ -99,7 +100,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
|||||||
}
|
}
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.showErrors(errors)
|
self.showErrors(errors)
|
||||||
} onFailure: { error in
|
} onError: { error in
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.show(error: error)
|
self.show(error: error)
|
||||||
//HUD.show(error: error)
|
//HUD.show(error: error)
|
||||||
@ -137,12 +138,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
|||||||
let csvString = try self.historyDataSource.makeCsv()
|
let csvString = try self.historyDataSource.makeCsv()
|
||||||
let tmpUrl = FileManager.default.tmpUrl(name: "history", ext: "csv")
|
let tmpUrl = FileManager.default.tmpUrl(name: "history", ext: "csv")
|
||||||
try csvString.write(to: tmpUrl, atomically: true, encoding: .utf8)
|
try csvString.write(to: tmpUrl, atomically: true, encoding: .utf8)
|
||||||
|
|
||||||
#if targetEnvironment(macCatalyst)
|
|
||||||
self.save(file: tmpUrl)
|
|
||||||
#else
|
|
||||||
self.shareFile(tmpUrl)
|
self.shareFile(tmpUrl)
|
||||||
#endif
|
|
||||||
} catch {
|
} catch {
|
||||||
self.show(error: error)
|
self.show(error: error)
|
||||||
}
|
}
|
||||||
@ -203,16 +199,6 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
|||||||
self.present(activityController, animated: true)
|
self.present(activityController, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func save(file url: URL) {
|
|
||||||
if #available(iOS 14, *) {
|
|
||||||
let controller = UIDocumentPickerViewController(forExporting: [url])
|
|
||||||
self.present(controller, animated: true)
|
|
||||||
} else {
|
|
||||||
let controller = UIDocumentPickerViewController(url: url, in: .exportToService)
|
|
||||||
present(controller, animated: true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Checking new number
|
// MARK: - Checking new number
|
||||||
|
|
||||||
func checkTapped(number: String) {
|
func checkTapped(number: String) {
|
||||||
@ -235,7 +221,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
|||||||
}
|
}
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.showErrors(errors)
|
self.showErrors(errors)
|
||||||
} onFailure: { error in
|
} onError: { error in
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.show(error: error)
|
self.show(error: error)
|
||||||
}
|
}
|
||||||
@ -338,7 +324,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
|||||||
}
|
}
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.showErrors(errors)
|
self.showErrors(errors)
|
||||||
} onFailure: { error in
|
} onError: { error in
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.show(error: error)
|
self.show(error: error)
|
||||||
}
|
}
|
||||||
@ -379,19 +365,19 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
|||||||
var eventSingle: Single<(event: VehicleEvent?, error: Error?)> = .just((event: nil, error: nil))
|
var eventSingle: Single<(event: VehicleEvent?, error: Error?)> = .just((event: nil, error: nil))
|
||||||
if action != .doNotSend {
|
if action != .doNotSend {
|
||||||
eventSingle = self.getEvent(for: action)
|
eventSingle = self.getEvent(for: action)
|
||||||
.flatMap { event in event.findAddress().map{ event }.catchAndReturn(event) }
|
.flatMap { event in event.findAddress().map{ event }.catchErrorJustReturn(event) }
|
||||||
.map { event -> (event: VehicleEvent?, error: Error?) in (event: event, error: nil) }
|
.map { event -> (event: VehicleEvent?, error: Error?) in (event: event, error: nil) }
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.catch { .just((event: nil, error: $0)) }
|
.catchError { .just((event: nil, error: $0)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
let checkSingle = Api.checkVehicle(by: number, notes: notes, events: events, force: force)
|
let checkSingle = Api.checkVehicle(by: number, notes: notes, events: events, force: force)
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.map { (vehicle: Vehicle) -> (vehicle: Vehicle, error: Error?) in
|
.map { (vehicle: Vehicle) -> (vehicle: Vehicle, error: Error?) in
|
||||||
try self.save(vehicle: vehicle)
|
try self.save(vehicle: vehicle)
|
||||||
return (vehicle: vehicle, error: nil)
|
return (vehicle: vehicle, error: nil)
|
||||||
}
|
}
|
||||||
.catch { error in
|
.catchError { error in
|
||||||
let realm = try Realm()
|
let realm = try Realm()
|
||||||
if let existingVehicle = realm.object(ofType: Vehicle.self, forPrimaryKey: number) {
|
if let existingVehicle = realm.object(ofType: Vehicle.self, forPrimaryKey: number) {
|
||||||
return .just((vehicle: existingVehicle, error: error))
|
return .just((vehicle: existingVehicle, error: error))
|
||||||
@ -433,12 +419,12 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
|||||||
} else {
|
} else {
|
||||||
if let event = eventResult.event {
|
if let event = eventResult.event {
|
||||||
return Api.add(event: event, to: vehicleResult.vehicle.getNumber())
|
return Api.add(event: event, to: vehicleResult.vehicle.getNumber())
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.map {
|
.map {
|
||||||
try self.save(vehicle: $0)
|
try self.save(vehicle: $0)
|
||||||
return (vehicle: $0, errors: errors)
|
return (vehicle: $0, errors: errors)
|
||||||
}
|
}
|
||||||
.catch { error in
|
.catchError { error in
|
||||||
errors.append(error)
|
errors.append(error)
|
||||||
return .just((vehicle: vehicleResult.vehicle, errors: errors))
|
return .just((vehicle: vehicleResult.vehicle, errors: errors))
|
||||||
}
|
}
|
||||||
|
|||||||
@ -145,77 +145,42 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
|||||||
// MARK: - UITableViewDelegate
|
// MARK: - UITableViewDelegate
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
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
|
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
|
||||||
|
let copy = UIAction(title: NSLocalizedString("Copy", comment: ""), image: UIImage(systemName: "doc.on.doc")) { action in
|
||||||
let copy = UIAction(title: NSLocalizedString("Copy", comment: ""),
|
self.copyEvent(index: indexPath.row)
|
||||||
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])
|
let share = UIAction(title: NSLocalizedString("Share", comment: ""), image: UIImage(systemName: "square.and.arrow.up")) { action in
|
||||||
|
self.shareEvent(index: indexPath.row)
|
||||||
|
}
|
||||||
|
|
||||||
|
let edit = UIAction(title: NSLocalizedString("Edit", comment: ""), image: UIImage(systemName: "pencil")) { action in
|
||||||
|
self.editEvent(index: indexPath.row)
|
||||||
|
}
|
||||||
|
|
||||||
|
let delete = UIAction(title: NSLocalizedString("Delete", comment: ""), image: UIImage(systemName: "trash"), attributes: .destructive) { action in
|
||||||
|
self.deleteEvent(index: indexPath.row)
|
||||||
|
}
|
||||||
|
|
||||||
|
return UIMenu(title: NSLocalizedString("Actions", comment: ""), children: [copy, share, edit, delete])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
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
|
let copy = UIContextualAction(style: .normal, title: NSLocalizedString("Copy", comment: "")) { action, view, completion in
|
||||||
self.copyEvent(event: event)
|
self.copyEvent(index: indexPath.row)
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
copy.image = UIImage(systemName: "doc.on.doc")
|
copy.image = UIImage(systemName: "doc.on.doc")
|
||||||
copy.backgroundColor = .systemBlue
|
copy.backgroundColor = .systemBlue
|
||||||
|
|
||||||
let delete = UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { action, view, completion in
|
let delete = UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { action, view, completion in
|
||||||
self.deleteEvent(event: event, completion: completion)
|
self.deleteEvent(index: indexPath.row, completion: completion)
|
||||||
}
|
}
|
||||||
delete.image = UIImage(systemName: "trash")
|
delete.image = UIImage(systemName: "trash")
|
||||||
|
|
||||||
let edit = UIContextualAction(style: .normal, title: NSLocalizedString("Edit", comment: "")) { action, view, completion in
|
let edit = UIContextualAction(style: .normal, title: NSLocalizedString("Edit", comment: "")) { action, view, completion in
|
||||||
self.editEvent(event: event)
|
self.editEvent(index: indexPath.row)
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
edit.image = UIImage(systemName: "pencil")
|
edit.image = UIImage(systemName: "pencil")
|
||||||
@ -241,19 +206,31 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
|||||||
|
|
||||||
// MARK: - Event actions
|
// MARK: - Event actions
|
||||||
|
|
||||||
func deleteEvent(event: VehicleEvent, completion: ((Bool) -> Void)? = nil) {
|
func deleteEvent(index: Int, completion: ((Bool) -> Void)? = nil) {
|
||||||
|
guard let vehicle = self.vehicle else {
|
||||||
|
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let event = vehicle.events[index]
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
Api.remove(event: event.id).observe(on: MainScheduler.instance).subscribe(onSuccess: { vehicle in
|
Api.remove(event: event.id).observeOn(MainScheduler.instance).subscribe(onSuccess: { vehicle in
|
||||||
let result = self.update(vehicle: vehicle)
|
let result = self.update(vehicle: vehicle)
|
||||||
completion?(result)
|
completion?(result)
|
||||||
}, onFailure: { error in
|
}, onError: { error in
|
||||||
completion?(false)
|
completion?(false)
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
print(error)
|
print(error)
|
||||||
}).disposed(by: self.bag)
|
}).disposed(by: self.bag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func editEvent(event: VehicleEvent) {
|
func editEvent(index: Int) {
|
||||||
|
guard let vehicle = self.vehicle else {
|
||||||
|
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let event = vehicle.events[index]
|
||||||
let sb = UIStoryboard(name: "Main", bundle: nil)
|
let sb = UIStoryboard(name: "Main", bundle: nil)
|
||||||
let controller = sb.instantiateViewController(identifier: "LocationEditController") as LocationEditController
|
let controller = sb.instantiateViewController(identifier: "LocationEditController") as LocationEditController
|
||||||
controller.title = NSLocalizedString("Edit event", comment: "")
|
controller.title = NSLocalizedString("Edit event", comment: "")
|
||||||
@ -264,8 +241,8 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
|||||||
self.navigationController?.popViewController(animated: true, completion: {
|
self.navigationController?.popViewController(animated: true, completion: {
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
Api.edit(event: newEvent)
|
Api.edit(event: newEvent)
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onFailure:
|
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
|
||||||
{ error in
|
{ error in
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
})
|
})
|
||||||
@ -275,8 +252,14 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
|||||||
self.navigationController?.pushViewController(controller, animated: true)
|
self.navigationController?.pushViewController(controller, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyEvent(event: VehicleEvent) {
|
func copyEvent(index: Int) {
|
||||||
|
guard let vehicle = self.vehicle else {
|
||||||
|
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var items: [String: Any] = [:]
|
var items: [String: Any] = [:]
|
||||||
|
let event = vehicle.events[index]
|
||||||
|
|
||||||
if let url = event.getMapLink() {
|
if let url = event.getMapLink() {
|
||||||
items[kUTTypeURL as String] = url
|
items[kUTTypeURL as String] = url
|
||||||
@ -295,29 +278,17 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
|||||||
self.setupBarButtonItems()
|
self.setupBarButtonItems()
|
||||||
}
|
}
|
||||||
|
|
||||||
func shareEvent(event: VehicleEvent) {
|
func shareEvent(index: Int) {
|
||||||
guard let url = event.getMapLink() else {
|
guard let vehicle = self.vehicle else {
|
||||||
|
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let event = vehicle.events[index]
|
||||||
|
if let url = event.getMapLink() {
|
||||||
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
||||||
self.present(controller, animated: true)
|
self.present(controller, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func openInAppleMaps(event: VehicleEvent) {
|
|
||||||
let coordinates = CLLocationCoordinate2D(latitude: event.latitude,
|
|
||||||
longitude: event.longitude)
|
|
||||||
let placemark = MKPlacemark(coordinate: coordinates)
|
|
||||||
let mapItem = MKMapItem(placemark: placemark)
|
|
||||||
mapItem.openInMaps()
|
|
||||||
}
|
|
||||||
|
|
||||||
func openInYandexMaps(event: VehicleEvent) {
|
|
||||||
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) {
|
@objc func addEvent(_ sender: UIBarButtonItem) {
|
||||||
@ -333,8 +304,8 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
|||||||
self.navigationController?.popViewController(animated: true, completion: {
|
self.navigationController?.popViewController(animated: true, completion: {
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
Api.add(event: newEvent, to: vehicle.getNumber())
|
Api.add(event: newEvent, to: vehicle.getNumber())
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onFailure:
|
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
|
||||||
{ error in
|
{ error in
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
})
|
})
|
||||||
@ -363,8 +334,8 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
|||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
event.id = UUID().uuidString
|
event.id = UUID().uuidString
|
||||||
Api.add(event: event, to: vehicle.getNumber())
|
Api.add(event: event, to: vehicle.getNumber())
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onFailure:
|
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
|
||||||
{ error in
|
{ error in
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -25,7 +25,7 @@ class GlobalEventsController: UIViewController {
|
|||||||
|
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
Api.events(with: self.filter)
|
Api.events(with: self.filter)
|
||||||
.observe(on: MainScheduler.init())
|
.observeOn(MainScheduler.init())
|
||||||
.subscribe(onSuccess: { events in
|
.subscribe(onSuccess: { events in
|
||||||
self.title = String.localizedStringWithFormat(NSLocalizedString("events found", comment: ""), events.count)
|
self.title = String.localizedStringWithFormat(NSLocalizedString("events found", comment: ""), events.count)
|
||||||
let pins = events.map(EventPin.init(event:))
|
let pins = events.map(EventPin.init(event:))
|
||||||
@ -33,9 +33,9 @@ class GlobalEventsController: UIViewController {
|
|||||||
self.map.addAnnotations(pins)
|
self.map.addAnnotations(pins)
|
||||||
self.map.centerOnPins()
|
self.map.centerOnPins()
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
}, onFailure: { error in
|
}) { error in
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
})
|
}
|
||||||
.disposed(by: self.bag)
|
.disposed(by: self.bag)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,24 +1,9 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import AutoCatCore
|
import AutoCatCore
|
||||||
|
|
||||||
// MARK: - Types
|
|
||||||
|
|
||||||
enum NumberType: Int, CaseIterable {
|
|
||||||
|
|
||||||
case plateNumber = 0
|
|
||||||
case vin = 1
|
|
||||||
|
|
||||||
var title: String {
|
|
||||||
switch self {
|
|
||||||
case .plateNumber: return "GRZ"
|
|
||||||
case .vin: return "VIN"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NewNumberController: UIViewController {
|
class NewNumberController: UIViewController {
|
||||||
|
|
||||||
// MARK: - Views
|
public var onCheck: ((String) -> Void)?
|
||||||
|
|
||||||
private lazy var keyboardView: PNKeyboard = {
|
private lazy var keyboardView: PNKeyboard = {
|
||||||
let keyboard = PNKeyboard(target: self.plateView)
|
let keyboard = PNKeyboard(target: self.plateView)
|
||||||
@ -36,26 +21,21 @@ class NewNumberController: UIViewController {
|
|||||||
return view
|
return view
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var vinField: UITextField = {
|
|
||||||
let view = UITextField()
|
|
||||||
view.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
view.borderStyle = .roundedRect
|
|
||||||
view.isHidden = true
|
|
||||||
return view
|
|
||||||
}()
|
|
||||||
|
|
||||||
private lazy var checkButton: ACButton = {
|
private lazy var checkButton: ACButton = {
|
||||||
let button = ACButton(title: NSLocalizedString("Check", comment: ""), onTap: check)
|
let button = ACButton(title: NSLocalizedString("Check", comment: ""), onTap: check)
|
||||||
button.isEnabled = false
|
button.isEnabled = false
|
||||||
button.contentEdgeInsets = .init(top: 0, left: 8, bottom: 0, right: 8)
|
button.contentEdgeInsets = .init(top: 0, left: 8, bottom: 0, right: 8)
|
||||||
button.accessibilityIdentifier = "checkButton"
|
button.accessibilityIdentifier = "checkButton"
|
||||||
button.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
|
||||||
return button
|
return button
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var stackView: UIStackView = .horizontal([
|
private lazy var stackView: UIStackView = {
|
||||||
plateView, vinField, checkButton
|
let stack = UIStackView(arrangedSubviews: [plateView, checkButton])
|
||||||
])
|
stack.axis = .horizontal
|
||||||
|
stack.spacing = 16
|
||||||
|
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
return stack
|
||||||
|
}()
|
||||||
|
|
||||||
private let titleLabel: UILabel = {
|
private let titleLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
@ -66,35 +46,13 @@ class NewNumberController: UIViewController {
|
|||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private lazy var mainStackView: UIStackView = .vertical([
|
private lazy var mainStackView: UIStackView = {
|
||||||
titleLabel,
|
let stack = UIStackView(arrangedSubviews: [titleLabel, stackView, keyboardView])
|
||||||
stackView,
|
stack.axis = .vertical
|
||||||
//settingsStackView,
|
stack.spacing = 16
|
||||||
keyboardView
|
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
])
|
return stack
|
||||||
|
}()
|
||||||
private let locationSwitcherView: UISegmentedControl = .segments(images: [
|
|
||||||
UIImage(systemName: "location.fill"),
|
|
||||||
UIImage(systemName: "location"),
|
|
||||||
UIImage(systemName: "location.slash")
|
|
||||||
])
|
|
||||||
|
|
||||||
private lazy var numTypeSwitcherView: UISegmentedControl = .segments(titles: NumberType.allCases.map(\.title))
|
|
||||||
.select(index: NumberType.plateNumber.rawValue)
|
|
||||||
.onValueChanged(onNumberTypeChanged)
|
|
||||||
|
|
||||||
private lazy var settingsStackView: UIStackView = .horizontal([
|
|
||||||
numTypeSwitcherView,
|
|
||||||
locationSwitcherView
|
|
||||||
])
|
|
||||||
.distribution(.fillProportionally)
|
|
||||||
|
|
||||||
// MARK: - Variables
|
|
||||||
|
|
||||||
public var onCheck: ((String) -> Void)?
|
|
||||||
private var numberType: NumberType = .plateNumber
|
|
||||||
|
|
||||||
// MARK: - Lifecycle
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
@ -121,27 +79,6 @@ class NewNumberController: UIViewController {
|
|||||||
func onNumberChanged() {
|
func onNumberChanged() {
|
||||||
checkButton.isEnabled = plateView.number?.isValid ?? false
|
checkButton.isEnabled = plateView.number?.isValid ?? false
|
||||||
}
|
}
|
||||||
|
|
||||||
func onNumberTypeChanged(_ index: Int) {
|
|
||||||
guard let type = NumberType(rawValue: index) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
numberType = type
|
|
||||||
|
|
||||||
switch type {
|
|
||||||
case .plateNumber:
|
|
||||||
plateView.isHidden = false
|
|
||||||
vinField.isHidden = true
|
|
||||||
keyboardView.target = plateView
|
|
||||||
keyboardView.type = .plateNumber
|
|
||||||
case .vin:
|
|
||||||
plateView.isHidden = true
|
|
||||||
vinField.isHidden = false
|
|
||||||
keyboardView.target = vinField
|
|
||||||
keyboardView.type = .vin
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NewNumberController: PNKeyboardDelegate {
|
extension NewNumberController: PNKeyboardDelegate {
|
||||||
|
|||||||
@ -138,11 +138,11 @@ class NotesController: UIViewController, UITableViewDataSource, UITableViewDeleg
|
|||||||
|
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
Api.add(notes: [note], to: vehicle.getNumber())
|
Api.add(notes: [note], to: vehicle.getNumber())
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.subscribe(onSuccess: {
|
.subscribe(onSuccess: {
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.update(vehicle: $0)
|
self.update(vehicle: $0)
|
||||||
}, onFailure: { error in
|
}, onError: { error in
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.show(error: error)
|
self.show(error: error)
|
||||||
})
|
})
|
||||||
@ -183,11 +183,11 @@ class NotesController: UIViewController, UITableViewDataSource, UITableViewDeleg
|
|||||||
let newNote = note.clone()
|
let newNote = note.clone()
|
||||||
newNote.text = noteText
|
newNote.text = noteText
|
||||||
Api.edit(note: newNote)
|
Api.edit(note: newNote)
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.subscribe(onSuccess: {
|
.subscribe(onSuccess: {
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.update(vehicle: $0)
|
self.update(vehicle: $0)
|
||||||
}, onFailure: { error in
|
}, onError: { error in
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.show(error: error)
|
self.show(error: error)
|
||||||
})
|
})
|
||||||
@ -217,12 +217,12 @@ class NotesController: UIViewController, UITableViewDataSource, UITableViewDeleg
|
|||||||
|
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
Api.remove(note: note.id)
|
Api.remove(note: note.id)
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.subscribe(onSuccess: { vehicle in
|
.subscribe(onSuccess: { vehicle in
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
let result = self.update(vehicle: vehicle)
|
let result = self.update(vehicle: vehicle)
|
||||||
completion?(result)
|
completion?(result)
|
||||||
}, onFailure: { error in
|
}, onError: { error in
|
||||||
completion?(false)
|
completion?(false)
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.show(error: error)
|
self.show(error: error)
|
||||||
|
|||||||
@ -71,11 +71,11 @@ class OsagoAddController: FormViewController {
|
|||||||
}
|
}
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
Api.checkOsago(number: number, vin: vin, date: date, token: token)
|
Api.checkOsago(number: number, vin: vin, date: date, token: token)
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.subscribe { vehicle in
|
.subscribe { vehicle in
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
self.onDone?(vehicle)
|
self.onDone?(vehicle)
|
||||||
} onFailure: { err in
|
} onError: { err in
|
||||||
HUD.show(error: err)
|
HUD.show(error: err)
|
||||||
}
|
}
|
||||||
.disposed(by: self.bag)
|
.disposed(by: self.bag)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import UIKit
|
|||||||
import AVFoundation
|
import AVFoundation
|
||||||
import RealmSwift
|
import RealmSwift
|
||||||
import RxSwift
|
import RxSwift
|
||||||
|
import RxRealm
|
||||||
import Intents
|
import Intents
|
||||||
import CoreSpotlight
|
import CoreSpotlight
|
||||||
import MobileCoreServices
|
import MobileCoreServices
|
||||||
@ -96,10 +97,10 @@ class RecordsController: UIViewController, UITableViewDelegate {
|
|||||||
|
|
||||||
let locationObservable = RxLocationManager.requestCurrentLocation()
|
let locationObservable = RxLocationManager.requestCurrentLocation()
|
||||||
.map(Optional.init)
|
.map(Optional.init)
|
||||||
.catchAndReturn(nil)
|
.catchErrorJustReturn(nil)
|
||||||
|
|
||||||
let recordObservable: Single<String> = recorder.requestPermissions()
|
let recordObservable: Single<String> = recorder.requestPermissions()
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.flatMap(self.makeStartSoundIfNeeded)
|
.flatMap(self.makeStartSoundIfNeeded)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
#if targetEnvironment(macCatalyst) || targetEnvironment(simulator)
|
#if targetEnvironment(macCatalyst) || targetEnvironment(simulator)
|
||||||
@ -140,7 +141,7 @@ class RecordsController: UIViewController, UITableViewDelegate {
|
|||||||
}
|
}
|
||||||
alert?.dismiss(animated: true)
|
alert?.dismiss(animated: true)
|
||||||
self.addButton.isEnabled = true
|
self.addButton.isEnabled = true
|
||||||
}, onFailure: { error in
|
}) { error in
|
||||||
if let alert = alert {
|
if let alert = alert {
|
||||||
alert.dismiss(animated: true) {
|
alert.dismiss(animated: true) {
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
@ -149,7 +150,7 @@ class RecordsController: UIViewController, UITableViewDelegate {
|
|||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
}
|
}
|
||||||
self.addButton.isEnabled = true
|
self.addButton.isEnabled = true
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func showRecordingAlert() -> UIAlertController {
|
func showRecordingAlert() -> UIAlertController {
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import LinkPresentation
|
|||||||
import RealmSwift
|
import RealmSwift
|
||||||
import Eureka
|
import Eureka
|
||||||
import AutoCatCore
|
import AutoCatCore
|
||||||
import SwiftEntryKit
|
|
||||||
import MobileCoreServices
|
|
||||||
|
|
||||||
class ReportController: FormViewController, MediaBrowserViewControllerDataSource, MediaBrowserViewControllerDelegate, UIActivityItemSource {
|
class ReportController: FormViewController, MediaBrowserViewControllerDataSource, MediaBrowserViewControllerDelegate, UIActivityItemSource {
|
||||||
|
|
||||||
@ -15,10 +13,6 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
|
|||||||
private var reportImageUrl: URL?
|
private var reportImageUrl: URL?
|
||||||
private let logoPlaceholder = UIImage(named: "SteeringWheel")
|
private let logoPlaceholder = UIImage(named: "SteeringWheel")
|
||||||
|
|
||||||
private let copyableTags = ["Model", "Year", "Color", "Category", "STP", "Japanese",
|
|
||||||
"PlateNumber", "VIN", "STS", "PTS",
|
|
||||||
"EngineNumber", "FuelType", "Volume", "PowerHP", "PowerKw"];
|
|
||||||
|
|
||||||
var vehicle: Vehicle? {
|
var vehicle: Vehicle? {
|
||||||
didSet {
|
didSet {
|
||||||
if isViewLoaded && self.view.window != nil {
|
if isViewLoaded && self.view.window != nil {
|
||||||
@ -160,43 +154,17 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
|
|||||||
func setupCopyBehaviour() {
|
func setupCopyBehaviour() {
|
||||||
|
|
||||||
for row in form.allRows {
|
for row in form.allRows {
|
||||||
if let labelRow = row as? LabelRow, copyableTags.contains(row.tag ?? "") {
|
if let labelRow = row as? LabelRow {
|
||||||
let doubleTap = UITapGestureRecognizer { _ in
|
let doubleTap = UITapGestureRecognizer { _ in
|
||||||
guard let text = labelRow.value else {
|
UIPasteboard.general.string = labelRow.value
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
UIPasteboard.general.string = text
|
|
||||||
let generator = UIImpactFeedbackGenerator(style: .rigid)
|
|
||||||
generator.impactOccurred()
|
|
||||||
let toastMessage = NSLocalizedString("Copied: ", comment: "") + text
|
|
||||||
self.showToast(text: toastMessage)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doubleTap.numberOfTapsRequired = 2
|
doubleTap.numberOfTapsRequired = 2
|
||||||
doubleTap.delaysTouchesBegan = true
|
|
||||||
labelRow.cell.addGestureRecognizer(doubleTap)
|
labelRow.cell.addGestureRecognizer(doubleTap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func showToast(text: String) {
|
|
||||||
let style = EKProperty.LabelStyle(
|
|
||||||
font: .systemFont(ofSize: 14),
|
|
||||||
color: .white, //.black,
|
|
||||||
alignment: .center
|
|
||||||
)
|
|
||||||
let labelContent = EKProperty.LabelContent(
|
|
||||||
text: text,
|
|
||||||
style: style
|
|
||||||
)
|
|
||||||
let contentView = EKNoteMessageView(with: labelContent)
|
|
||||||
|
|
||||||
var attributes: EKAttributes = .bottomFloat //.toast
|
|
||||||
attributes.entryBackground = .visualEffect(style: EKAttributes.BackgroundStyle.BlurStyle(light: .dark, dark: .light)) //.color(color: .init(red: 0, green: 196, blue: 0))
|
|
||||||
SwiftEntryKit.display(entry: contentView, using: attributes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func update(row tag: String, with value: String) {
|
func update(row tag: String, with value: String) {
|
||||||
if let row = self.form.rowBy(tag: tag) as? LabelRow {
|
if let row = self.form.rowBy(tag: tag) as? LabelRow {
|
||||||
row.value = value
|
row.value = value
|
||||||
@ -216,8 +184,8 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
|
|||||||
self.update(row: "Year", with: String(self.vehicle?.year ?? 0))
|
self.update(row: "Year", with: String(self.vehicle?.year ?? 0))
|
||||||
self.update(row: "Color", with: self.vehicle?.color ?? "<unknown>")
|
self.update(row: "Color", with: self.vehicle?.color ?? "<unknown>")
|
||||||
self.update(row: "Category", with: self.vehicle?.category ?? "<unknown>")
|
self.update(row: "Category", with: self.vehicle?.category ?? "<unknown>")
|
||||||
self.update(row: "STP", with: self.stringFromBool(self.vehicle?.isRightWheel, yes: NSLocalizedString("Right", comment: ""), no: NSLocalizedString("Left", comment: "")))
|
self.update(row: "STP", with: self.stringFromBool(self.vehicle?.isRightWheel.value, yes: NSLocalizedString("Right", comment: ""), no: NSLocalizedString("Left", comment: "")))
|
||||||
self.update(row: "Japanese", with: self.stringFromBool(self.vehicle?.isJapanese, yes: NSLocalizedString("Yes", comment: ""), no: NSLocalizedString("No", comment: "")))
|
self.update(row: "Japanese", with: self.stringFromBool(self.vehicle?.isJapanese.value, yes: NSLocalizedString("Yes", comment: ""), no: NSLocalizedString("No", comment: "")))
|
||||||
|
|
||||||
var num = self.vehicle?.getNumber() ?? "<unknown>"
|
var num = self.vehicle?.getNumber() ?? "<unknown>"
|
||||||
if self.vehicle?.outdated ?? false, let current = self.vehicle?.currentNumber {
|
if self.vehicle?.outdated ?? false, let current = self.vehicle?.currentNumber {
|
||||||
@ -230,9 +198,9 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
|
|||||||
self.update(row: "PTS", with: self.vehicle?.pts ?? "<unknown>")
|
self.update(row: "PTS", with: self.vehicle?.pts ?? "<unknown>")
|
||||||
self.update(row: "EngineNumber", with: self.vehicle?.engine?.number ?? "<unknown>")
|
self.update(row: "EngineNumber", with: self.vehicle?.engine?.number ?? "<unknown>")
|
||||||
self.update(row: "FuelType", with: self.vehicle?.engine?.fuelType ?? "<unknown>")
|
self.update(row: "FuelType", with: self.vehicle?.engine?.fuelType ?? "<unknown>")
|
||||||
self.update(row: "Volume", with: String(self.vehicle?.engine?.volume ?? 0))
|
self.update(row: "Volume", with: String(self.vehicle?.engine?.volume.value ?? 0))
|
||||||
self.update(row: "PowerHP", with: String(self.vehicle?.engine?.powerHp ?? 0))
|
self.update(row: "PowerHP", with: String(self.vehicle?.engine?.powerHp ?? 0))
|
||||||
self.update(row: "PowerKw", with: String(self.vehicle?.engine?.powerKw ?? 0))
|
self.update(row: "PowerKw", with: String(self.vehicle?.engine?.powerKw.value ?? 0))
|
||||||
self.update(row: "Events", with: String(self.vehicle?.events.count ?? 0))
|
self.update(row: "Events", with: String(self.vehicle?.events.count ?? 0))
|
||||||
self.update(row: "OSAGO", with: String(self.vehicle?.osagoContracts.count ?? 0))
|
self.update(row: "OSAGO", with: String(self.vehicle?.osagoContracts.count ?? 0))
|
||||||
self.update(row: "Owners", with: String(self.vehicle?.ownershipPeriods.count ?? 0))
|
self.update(row: "Owners", with: String(self.vehicle?.ownershipPeriods.count ?? 0))
|
||||||
@ -349,29 +317,16 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
|
|||||||
let shareLink = UIAlertAction(title: NSLocalizedString("As link", comment: ""), style: .default) { _ in
|
let shareLink = UIAlertAction(title: NSLocalizedString("As link", comment: ""), style: .default) { _ in
|
||||||
guard let vehicle = self.vehicle else { return }
|
guard let vehicle = self.vehicle else { return }
|
||||||
|
|
||||||
if let jwt = try? JWT<EmptyPayload>.generate(for: vehicle.getNumber()),
|
if let jwt = try? JWT<EmptyPayload>.generate(for: vehicle.getNumber()), let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt) {
|
||||||
let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt)
|
|
||||||
{
|
|
||||||
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
||||||
controller.popoverPresentationController?.barButtonItem = sender
|
controller.popoverPresentationController?.barButtonItem = sender
|
||||||
self.present(controller, animated: true)
|
self.present(controller, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let copyLink = UIAlertAction(title: NSLocalizedString("Copy link to report", comment: ""), style: .default) { _ in
|
|
||||||
guard let vehicle = self.vehicle else { return }
|
|
||||||
|
|
||||||
if let jwt = try? JWT<EmptyPayload>.generate(for: vehicle.getNumber()),
|
|
||||||
let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt)
|
|
||||||
{
|
|
||||||
UIPasteboard.general.string = url.absoluteString
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sheet.addAction(shareImage)
|
sheet.addAction(shareImage)
|
||||||
sheet.addAction(shareTextAndImage)
|
sheet.addAction(shareTextAndImage)
|
||||||
sheet.addAction(shareLink)
|
sheet.addAction(shareLink)
|
||||||
sheet.addAction(copyLink)
|
|
||||||
sheet.addAction(cancel)
|
sheet.addAction(cancel)
|
||||||
self.present(sheet, animated: true, completion: nil)
|
self.present(sheet, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import PKHUD
|
|||||||
import ExceptionCatcher
|
import ExceptionCatcher
|
||||||
import AutoCatCore
|
import AutoCatCore
|
||||||
|
|
||||||
class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDelegate, UIScrollViewDelegate, UISearchBarDelegate {
|
class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDelegate, UIScrollViewDelegate {
|
||||||
|
|
||||||
@IBOutlet weak var tableView: UITableView!
|
@IBOutlet weak var tableView: UITableView!
|
||||||
@IBOutlet weak var showMapButton: UIBarButtonItem?
|
@IBOutlet weak var showMapButton: UIBarButtonItem?
|
||||||
@ -20,9 +20,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
|||||||
private lazy var searchController: UISearchController = .default
|
private lazy var searchController: UISearchController = .default
|
||||||
.placeholder(NSLocalizedString("Search plate numbers", comment: ""))
|
.placeholder(NSLocalizedString("Search plate numbers", comment: ""))
|
||||||
.resultsUpdater(self)
|
.resultsUpdater(self)
|
||||||
.searchBarDelegate(self)
|
|
||||||
.makeDumb()
|
.makeDumb()
|
||||||
.scopeButtons(SearchScope.allCases.map(\.title))
|
|
||||||
|
|
||||||
private var refreshControl = UIRefreshControl()
|
private var refreshControl = UIRefreshControl()
|
||||||
private var datasource: RxSectionedDataSource<Vehicle,VehicleCell>!
|
private var datasource: RxSectionedDataSource<Vehicle,VehicleCell>!
|
||||||
@ -74,9 +72,9 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
|||||||
}
|
}
|
||||||
return Api.getVehicles(with: filter, pageToken: self.datasource.pageToken)
|
return Api.getVehicles(with: filter, pageToken: self.datasource.pageToken)
|
||||||
.do(onError: { print($0) })
|
.do(onError: { print($0) })
|
||||||
.catchAndReturn(PagedResponse<Vehicle>())
|
.catchErrorJustReturn(PagedResponse<Vehicle>())
|
||||||
}
|
}
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.do(onNext: {
|
.do(onNext: {
|
||||||
if let count = $0.count {
|
if let count = $0.count {
|
||||||
self.navigationItem.title = String.localizedStringWithFormat(NSLocalizedString("vehicles found", comment: ""), count)
|
self.navigationItem.title = String.localizedStringWithFormat(NSLocalizedString("vehicles found", comment: ""), count)
|
||||||
@ -138,20 +136,9 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
|||||||
|
|
||||||
self.filter.searchString = newQuery
|
self.filter.searchString = newQuery
|
||||||
self.filter.needReset = true
|
self.filter.needReset = true
|
||||||
self.filter.scope = SearchScope(rawValue: searchController.searchBar.selectedScopeButtonIndex) ?? .plateNumber
|
|
||||||
|
|
||||||
self.filterRelay.accept(self.filter)
|
self.filterRelay.accept(self.filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
|
|
||||||
guard let scope = SearchScope(rawValue: selectedScope) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
filter.scope = scope
|
|
||||||
filterRelay.accept(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: NavigationBar actions
|
// MARK: NavigationBar actions
|
||||||
|
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
@ -196,7 +183,6 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
|||||||
self.filter = controller.filter
|
self.filter = controller.filter
|
||||||
self.datasource.setSortParameter(self.filter.sortBy ?? .updatedDate)
|
self.datasource.setSortParameter(self.filter.sortBy ?? .updatedDate)
|
||||||
self.filter.needReset = true
|
self.filter.needReset = true
|
||||||
self.filter.scope = SearchScope(rawValue: self.searchController.searchBar.selectedScopeButtonIndex) ?? .plateNumber
|
|
||||||
self.filterRelay.accept(self.filter)
|
self.filterRelay.accept(self.filter)
|
||||||
}
|
}
|
||||||
self.navigationController?.pushViewController(controller, animated: true)
|
self.navigationController?.pushViewController(controller, animated: true)
|
||||||
@ -217,7 +203,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
|||||||
showProgress()
|
showProgress()
|
||||||
|
|
||||||
Api.getVehicles(with: filter, pageSize: 0)
|
Api.getVehicles(with: filter, pageSize: 0)
|
||||||
.observe(on: MainScheduler.instance)
|
.observeOn(MainScheduler.instance)
|
||||||
.subscribe(onSuccess: { resp in
|
.subscribe(onSuccess: { resp in
|
||||||
self.hideProgress()
|
self.hideProgress()
|
||||||
|
|
||||||
@ -232,15 +218,15 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
|||||||
do {
|
do {
|
||||||
let tmpUrl = FileManager.default.tmpUrl(name: "search", ext: "csv")
|
let tmpUrl = FileManager.default.tmpUrl(name: "search", ext: "csv")
|
||||||
try csvString.write(to: tmpUrl, atomically: true, encoding: .utf8)
|
try csvString.write(to: tmpUrl, atomically: true, encoding: .utf8)
|
||||||
#if targetEnvironment(macCatalyst)
|
#if targetEnvironment(macCatalyst)
|
||||||
self.save(file: tmpUrl)
|
self.save(file: tmpUrl)
|
||||||
#else
|
#else
|
||||||
self.share(file: tmpUrl)
|
self.share(file: tmpUrl)
|
||||||
#endif
|
#endif
|
||||||
} catch {
|
} catch {
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
}
|
}
|
||||||
}, onFailure: { error in
|
}, onError: { error in
|
||||||
self.hideProgress()
|
self.hideProgress()
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
})
|
})
|
||||||
@ -292,7 +278,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
|||||||
|
|
||||||
func update(vehicle: Vehicle, at indexPath: IndexPath) {
|
func update(vehicle: Vehicle, at indexPath: IndexPath) {
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
Api.checkVehicle(by: vehicle.getNumber(), notes: Array(vehicle.notes), events: [], force: true).observe(on: MainScheduler.instance).subscribe { newVehicle in
|
Api.checkVehicle(by: vehicle.getNumber(), notes: Array(vehicle.notes), events: [], force: true).observeOn(MainScheduler.instance).subscribe { newVehicle in
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
do {
|
do {
|
||||||
let realm = try Realm()
|
let realm = try Realm()
|
||||||
@ -309,7 +295,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
|||||||
let frozenVehicle = newVehicle.realm != nil ? newVehicle.clone() : newVehicle
|
let frozenVehicle = newVehicle.realm != nil ? newVehicle.clone() : newVehicle
|
||||||
self.datasource.set(item: frozenVehicle, at: indexPath)
|
self.datasource.set(item: frozenVehicle, at: indexPath)
|
||||||
self.updateDetailController(with: frozenVehicle)
|
self.updateDetailController(with: frozenVehicle)
|
||||||
} onFailure: { err in
|
} onError: { err in
|
||||||
HUD.show(error: err)
|
HUD.show(error: err)
|
||||||
}.disposed(by: self.bag)
|
}.disposed(by: self.bag)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ extension AVAudioSession {
|
|||||||
do {
|
do {
|
||||||
try self.setCategory(category, mode: .default, options: [])
|
try self.setCategory(category, mode: .default, options: [])
|
||||||
} catch {
|
} catch {
|
||||||
observer(.failure(error))
|
observer(.error(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
return Disposables.create()
|
return Disposables.create()
|
||||||
|
|||||||
@ -82,13 +82,13 @@ extension Vehicle {
|
|||||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Category", value: self.category ?? "<unknown>", context: ctx)
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Category", value: self.category ?? "<unknown>", context: ctx)
|
||||||
y += cellHeight
|
y += cellHeight
|
||||||
var position = "Unknown"
|
var position = "Unknown"
|
||||||
if let rightWheel = self.isRightWheel {
|
if let rightWheel = self.isRightWheel.value {
|
||||||
position = rightWheel ? "Right" : "Left"
|
position = rightWheel ? "Right" : "Left"
|
||||||
}
|
}
|
||||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Steering wheel position", value: position, context: ctx)
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Steering wheel position", value: position, context: ctx)
|
||||||
y += cellHeight
|
y += cellHeight
|
||||||
var japanese = "<Unknown>"
|
var japanese = "<Unknown>"
|
||||||
if let isJapanese = self.isJapanese {
|
if let isJapanese = self.isJapanese.value {
|
||||||
japanese = isJapanese ? "Yes" : "No"
|
japanese = isJapanese ? "Yes" : "No"
|
||||||
}
|
}
|
||||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Japanese", value: japanese, lineMargin: 0, context: ctx)
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Japanese", value: japanese, lineMargin: 0, context: ctx)
|
||||||
@ -115,11 +115,11 @@ extension Vehicle {
|
|||||||
y += cellHeight
|
y += cellHeight
|
||||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Fuel type", value: self.engine?.fuelType ?? "<unknown>", context: ctx)
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Fuel type", value: self.engine?.fuelType ?? "<unknown>", context: ctx)
|
||||||
y += cellHeight
|
y += cellHeight
|
||||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Volume (cm³)", value: String(self.engine?.volume ?? 0), context: ctx)
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Volume (cm³)", value: String(self.engine?.volume.value ?? 0), context: ctx)
|
||||||
y += cellHeight
|
y += cellHeight
|
||||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (HP)", value: String(self.engine?.powerHp ?? 0), context: ctx)
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (HP)", value: String(self.engine?.powerHp ?? 0), context: ctx)
|
||||||
y += cellHeight
|
y += cellHeight
|
||||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (kw)", value: String(self.engine?.powerKw ?? 0), context: ctx)
|
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (kw)", value: String(self.engine?.powerKw.value ?? 0), context: ctx)
|
||||||
y += cellHeight + 32
|
y += cellHeight + 32
|
||||||
|
|
||||||
"OWNERSHIP PERIODS (\(self.ownershipPeriods.count))".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
"OWNERSHIP PERIODS (\(self.ownershipPeriods.count))".draw(with: CGRect(x: 15, y: y, width: w - 15, height: 24), options: .usesLineFragmentOrigin, attributes: headerAttributes, context: nil)
|
||||||
@ -216,11 +216,11 @@ extension Vehicle {
|
|||||||
if let color = self.color { text += "Color: \(color)\n" }
|
if let color = self.color { text += "Color: \(color)\n" }
|
||||||
if let category = self.category { text += "Category: \(category)\n" }
|
if let category = self.category { text += "Category: \(category)\n" }
|
||||||
var position = "Unknown"
|
var position = "Unknown"
|
||||||
if let rightWheel = self.isRightWheel {
|
if let rightWheel = self.isRightWheel.value {
|
||||||
position = rightWheel ? "Right" : "Left"
|
position = rightWheel ? "Right" : "Left"
|
||||||
}
|
}
|
||||||
var japanese = "<Unknown>"
|
var japanese = "<Unknown>"
|
||||||
if let isJapanese = self.isJapanese {
|
if let isJapanese = self.isJapanese.value {
|
||||||
japanese = isJapanese ? "Yes" : "No"
|
japanese = isJapanese ? "Yes" : "No"
|
||||||
}
|
}
|
||||||
text += "Steering wheel position: \(position)\n"
|
text += "Steering wheel position: \(position)\n"
|
||||||
|
|||||||
@ -2,10 +2,6 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>LSApplicationQueriesSchemes</key>
|
|
||||||
<array>
|
|
||||||
<string>yandexmaps</string>
|
|
||||||
</array>
|
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
|||||||
@ -163,7 +163,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
guard let rootController = self.window?.rootViewController else { return }
|
guard let rootController = self.window?.rootViewController else { return }
|
||||||
|
|
||||||
HUD.show(.progress)
|
HUD.show(.progress)
|
||||||
_ = Api.getReport(for: number).observe(on: MainScheduler.instance).subscribe { vehicle in
|
_ = Api.getReport(for: number).observeOn(MainScheduler.instance).subscribe { vehicle in
|
||||||
let sb = UIStoryboard(name: "Main", bundle: nil)
|
let sb = UIStoryboard(name: "Main", bundle: nil)
|
||||||
let controller = sb.instantiateViewController(identifier: "ReportController") as ReportController
|
let controller = sb.instantiateViewController(identifier: "ReportController") as ReportController
|
||||||
controller.vehicle = vehicle
|
controller.vehicle = vehicle
|
||||||
@ -172,7 +172,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||||||
controller.navigationItem.leftBarButtonItem = BlockBarButtonItem(barButtonSystemItem: .close) { _ in nav.dismiss(animated: true) }
|
controller.navigationItem.leftBarButtonItem = BlockBarButtonItem(barButtonSystemItem: .close) { _ in nav.dismiss(animated: true) }
|
||||||
rootController.present(nav, animated: true)
|
rootController.present(nav, animated: true)
|
||||||
HUD.hide()
|
HUD.hide()
|
||||||
} onFailure: { error in
|
} onError: { error in
|
||||||
HUD.show(error: error)
|
HUD.show(error: error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import UIKit
|
|||||||
|
|
||||||
// MARK: - MediaBrowserViewControllerDataSource protocol
|
// MARK: - MediaBrowserViewControllerDataSource protocol
|
||||||
/// Protocol to supply media browser contents.
|
/// Protocol to supply media browser contents.
|
||||||
public protocol MediaBrowserViewControllerDataSource: AnyObject {
|
public protocol MediaBrowserViewControllerDataSource: class {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Completion block for passing requested media image with details.
|
Completion block for passing requested media image with details.
|
||||||
@ -88,7 +88,7 @@ extension MediaBrowserViewControllerDataSource {
|
|||||||
|
|
||||||
// MARK: - MediaBrowserViewControllerDelegate protocol
|
// MARK: - MediaBrowserViewControllerDelegate protocol
|
||||||
|
|
||||||
public protocol MediaBrowserViewControllerDelegate: AnyObject {
|
public protocol MediaBrowserViewControllerDelegate: class {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Method invoked on scrolling to next/previous media items.
|
Method invoked on scrolling to next/previous media items.
|
||||||
|
|||||||
@ -45,25 +45,25 @@ class Recorder {
|
|||||||
break
|
break
|
||||||
case .denied:
|
case .denied:
|
||||||
let error = CocoaError.error("Access error", reason: "Access to speech recognition is denied", suggestion: "Please give permission to use speech recognition in system settings")
|
let error = CocoaError.error("Access error", reason: "Access to speech recognition is denied", suggestion: "Please give permission to use speech recognition in system settings")
|
||||||
observer(.failure(error))
|
observer(.error(error))
|
||||||
break
|
break
|
||||||
case .restricted:
|
case .restricted:
|
||||||
let error = CocoaError.error("Access error", reason: "Speech recognition is restricted on this device")
|
let error = CocoaError.error("Access error", reason: "Speech recognition is restricted on this device")
|
||||||
observer(.failure(error))
|
observer(.error(error))
|
||||||
break
|
break
|
||||||
case .notDetermined:
|
case .notDetermined:
|
||||||
let error = CocoaError.error("Access error", reason: "Speech recognition status is not yet determined")
|
let error = CocoaError.error("Access error", reason: "Speech recognition status is not yet determined")
|
||||||
observer(.failure(error))
|
observer(.error(error))
|
||||||
break
|
break
|
||||||
@unknown default:
|
@unknown default:
|
||||||
let error = CocoaError.error("Access error", reason: "Unknown error accessing speech recognizer")
|
let error = CocoaError.error("Access error", reason: "Unknown error accessing speech recognizer")
|
||||||
observer(.failure(error))
|
observer(.error(error))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let error = CocoaError.error("Access error", reason: "Access to microphone is denied", suggestion: "Please give permission to use microphone in system settings")
|
let error = CocoaError.error("Access error", reason: "Access to microphone is denied", suggestion: "Please give permission to use microphone in system settings")
|
||||||
observer(.failure(error))
|
observer(.error(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,13 +78,13 @@ class Recorder {
|
|||||||
|
|
||||||
return Single<String>.create { observer in
|
return Single<String>.create { observer in
|
||||||
guard let aac = AVAudioFormat(settings: self.recordingSettings) else {
|
guard let aac = AVAudioFormat(settings: self.recordingSettings) else {
|
||||||
observer(.failure(CocoaError.error("Recording error", reason: "Format not supported")))
|
observer(.error(CocoaError.error("Recording error", reason: "Format not supported")))
|
||||||
return Disposables.create()
|
return Disposables.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtAudioFileCreateWithURL(file as CFURL, kAudioFileM4AType, aac.streamDescription, nil, AudioFileFlags.eraseFile.rawValue, &self.fileRef)
|
ExtAudioFileCreateWithURL(file as CFURL, kAudioFileM4AType, aac.streamDescription, nil, AudioFileFlags.eraseFile.rawValue, &self.fileRef)
|
||||||
guard let fileRef = self.fileRef else {
|
guard let fileRef = self.fileRef else {
|
||||||
observer(.failure(CocoaError.error(CocoaError.Code.fileWriteUnknown)))
|
observer(.error(CocoaError.error(CocoaError.Code.fileWriteUnknown)))
|
||||||
return Disposables.create()
|
return Disposables.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ class Recorder {
|
|||||||
self.engine.prepare()
|
self.engine.prepare()
|
||||||
try self.engine.start()
|
try self.engine.start()
|
||||||
} catch {
|
} catch {
|
||||||
observer(.failure(error))
|
observer(.error(error))
|
||||||
}
|
}
|
||||||
|
|
||||||
return Disposables.create {
|
return Disposables.create {
|
||||||
|
|||||||
@ -15,57 +15,28 @@ enum PNButtonType {
|
|||||||
case done
|
case done
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PNKeyboardType {
|
|
||||||
|
|
||||||
case plateNumber
|
|
||||||
case vin
|
|
||||||
}
|
|
||||||
|
|
||||||
class PNButton: UIButton {
|
class PNButton: UIButton {
|
||||||
private(set) var type: PNButtonType
|
private(set) var type: PNButtonType
|
||||||
private var keyboardType: PNKeyboardType = .plateNumber
|
|
||||||
private var rectLayer = CAShapeLayer()
|
private var rectLayer = CAShapeLayer()
|
||||||
private var bgColor = UIColor(named: "KeyBackground")
|
private var bgColor = UIColor(named: "KeyBackground")
|
||||||
|
|
||||||
weak var delegate: PNButtonDelegate?
|
weak var delegate: PNButtonDelegate?
|
||||||
|
|
||||||
var letterFont: UIFont? {
|
init(letter: Character) {
|
||||||
|
|
||||||
switch keyboardType {
|
|
||||||
case .plateNumber:
|
|
||||||
return UIFont(name: "RoadNumbers", size: 36)
|
|
||||||
case .vin:
|
|
||||||
return .systemFont(ofSize: 24)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var digitFont: UIFont? {
|
|
||||||
|
|
||||||
switch keyboardType {
|
|
||||||
case .plateNumber:
|
|
||||||
return UIFont(name: "RoadNumbersCyr-Regular", size: 30)
|
|
||||||
case .vin:
|
|
||||||
return .systemFont(ofSize: 24)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init(letter: Character, keyboardType: PNKeyboardType = .plateNumber) {
|
|
||||||
self.type = .symbol(String(letter))
|
self.type = .symbol(String(letter))
|
||||||
self.keyboardType = keyboardType
|
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
self.setup()
|
self.setup()
|
||||||
self.titleLabel?.font = letterFont
|
self.titleLabel?.font = UIFont(name: "RoadNumbers", size: 36)
|
||||||
let title = String(Constants.pnLettersMap[letter] ?? letter)
|
let title = String(Constants.pnLettersMap[letter] ?? letter)
|
||||||
self.setTitle(title, for: .normal)
|
self.setTitle(title, for: .normal)
|
||||||
self.setTitleColor(.label, for: .normal)
|
self.setTitleColor(.label, for: .normal)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(digit: Int, keyboardType: PNKeyboardType = .plateNumber) {
|
init(digit: Int) {
|
||||||
self.type = .symbol(String(digit))
|
self.type = .symbol(String(digit))
|
||||||
self.keyboardType = keyboardType
|
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
self.setup()
|
self.setup()
|
||||||
self.titleLabel?.font = digitFont
|
self.titleLabel?.font = UIFont(name: "RoadNumbersCyr-Regular", size: 30)
|
||||||
let character = Character(String(digit))
|
let character = Character(String(digit))
|
||||||
let title = String(Constants.pnLettersMap[character] ?? character)
|
let title = String(Constants.pnLettersMap[character] ?? character)
|
||||||
self.setTitle(title, for: .normal)
|
self.setTitle(title, for: .normal)
|
||||||
@ -127,52 +98,20 @@ class PNButton: UIButton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
||||||
public weak var target: UIKeyInput?
|
private weak var target: UIKeyInput?
|
||||||
weak var delegate: PNKeyboardDelegate?
|
weak var delegate: PNKeyboardDelegate?
|
||||||
|
|
||||||
private let insets: UIEdgeInsets
|
private let insets: UIEdgeInsets
|
||||||
|
|
||||||
public var type: PNKeyboardType {
|
init(target: UIKeyInput, insets: UIEdgeInsets = .zero) {
|
||||||
didSet {
|
|
||||||
setupButtons()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var letters: [Character] {
|
|
||||||
|
|
||||||
switch type {
|
|
||||||
case .plateNumber:
|
|
||||||
return Array(Constants.pnLettersMap.keys)
|
|
||||||
case .vin:
|
|
||||||
return Constants.vinLetters
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var lettersWidthConstraint: NSLayoutConstraint?
|
|
||||||
private var digitsWidthConstraint: NSLayoutConstraint?
|
|
||||||
|
|
||||||
var mainStack: UIStackView = .horizontal([])
|
|
||||||
//.distribution(.fillProportionally)
|
|
||||||
.spacing(16)
|
|
||||||
|
|
||||||
init(target: UIKeyInput, type: PNKeyboardType = .plateNumber, insets: UIEdgeInsets = .zero) {
|
|
||||||
self.target = target
|
self.target = target
|
||||||
self.insets = insets
|
self.insets = insets
|
||||||
self.type = type
|
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
|
|
||||||
let blurEffectView = UIVisualEffectView(effect: UIBlurEffect())
|
let blurEffectView = UIVisualEffectView(effect: UIBlurEffect())
|
||||||
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
self.addSubview(blurEffectView)
|
self.addSubview(blurEffectView)
|
||||||
self.addSubview(mainStack)
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
mainStack.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: insets.left),
|
|
||||||
mainStack.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -insets.right),
|
|
||||||
mainStack.topAnchor.constraint(equalTo: self.topAnchor, constant: insets.top),
|
|
||||||
mainStack.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: -insets.bottom)
|
|
||||||
])
|
|
||||||
|
|
||||||
self.setupButtons()
|
self.setupButtons()
|
||||||
}
|
}
|
||||||
@ -181,53 +120,14 @@ class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layoutSubviews() {
|
|
||||||
super.layoutSubviews()
|
|
||||||
|
|
||||||
let lettersMult: CGFloat = type == .plateNumber ? 0.5 : 2.0/3.0
|
|
||||||
let digitsMult: CGFloat = type == .plateNumber ? 0.5 : 1.0/3.0
|
|
||||||
let availableWidth = frame.width - mainStack.spacing
|
|
||||||
|
|
||||||
let newLettersWidth = availableWidth*lettersMult
|
|
||||||
let newDigitsWidth = availableWidth*digitsMult
|
|
||||||
|
|
||||||
let needChangeConstraints = lettersWidthConstraint?.constant != newLettersWidth
|
|
||||||
|| digitsWidthConstraint?.constant != newDigitsWidth
|
|
||||||
|
|
||||||
if needChangeConstraints {
|
|
||||||
lettersWidthConstraint?.constant = newLettersWidth
|
|
||||||
digitsWidthConstraint?.constant = newDigitsWidth
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func letterRows(from buttons: [PNButton]) -> [UIView] {
|
|
||||||
|
|
||||||
switch type {
|
|
||||||
case .plateNumber:
|
|
||||||
return [
|
|
||||||
createLetterStack([buttons[0], buttons[1], buttons[2]]),
|
|
||||||
createLetterStack([buttons[3], buttons[4], buttons[5]]),
|
|
||||||
createLetterStack([buttons[6], buttons[7], buttons[8]]),
|
|
||||||
createLetterStack([buttons[9], buttons[10], buttons[11]])
|
|
||||||
]
|
|
||||||
case .vin:
|
|
||||||
return [
|
|
||||||
createLetterStack([buttons[0], buttons[1], buttons[2], buttons[3], buttons[4], buttons[5]]),
|
|
||||||
createLetterStack([buttons[6], buttons[7], buttons[8], buttons[9], buttons[10], buttons[11]]),
|
|
||||||
createLetterStack([buttons[12], buttons[13], buttons[14], buttons[15], buttons[16], buttons[17]]),
|
|
||||||
createLetterStack([buttons[18], buttons[19], buttons[20], buttons[21], buttons[22]])
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupButtons() {
|
func setupButtons() {
|
||||||
let letterButtons: [PNButton] = letters.sorted().map { letter in
|
let letters: [PNButton] = Constants.pnLettersMap.keys.sorted().map { letter in
|
||||||
let button = PNButton(letter: letter, keyboardType: type)
|
let button = PNButton(letter: letter)
|
||||||
button.delegate = self
|
button.delegate = self
|
||||||
return button
|
return button
|
||||||
}
|
}
|
||||||
let digits: [PNButton] = [1,2,3,4,5,6,7,8,9,0].map { digit in
|
let digits: [PNButton] = [1,2,3,4,5,6,7,8,9,0].map { digit in
|
||||||
let button = PNButton(digit: digit, keyboardType: type)
|
let button = PNButton(digit: digit)
|
||||||
button.delegate = self
|
button.delegate = self
|
||||||
return button
|
return button
|
||||||
}
|
}
|
||||||
@ -239,8 +139,14 @@ class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
|||||||
done.setBacgroundColor(color: .systemBlue)
|
done.setBacgroundColor(color: .systemBlue)
|
||||||
done.tintColor = .white
|
done.tintColor = .white
|
||||||
|
|
||||||
let rows = letterRows(from: letterButtons)
|
let letterRows = [
|
||||||
let lettersStack = UIStackView(arrangedSubviews: rows)
|
self.createLetterStack([letters[0], letters[1], letters[2]]),
|
||||||
|
self.createLetterStack([letters[3], letters[4], letters[5]]),
|
||||||
|
self.createLetterStack([letters[6], letters[7], letters[8]]),
|
||||||
|
self.createLetterStack([letters[9], letters[10], letters[11]])
|
||||||
|
]
|
||||||
|
|
||||||
|
let lettersStack = UIStackView(arrangedSubviews: letterRows)
|
||||||
lettersStack.axis = .vertical
|
lettersStack.axis = .vertical
|
||||||
lettersStack.distribution = .fillEqually
|
lettersStack.distribution = .fillEqually
|
||||||
//lettersStack.spacing = 8
|
//lettersStack.spacing = 8
|
||||||
@ -257,15 +163,18 @@ class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
|||||||
digitsStack.distribution = .fillEqually
|
digitsStack.distribution = .fillEqually
|
||||||
//digitsStack.spacing = 8
|
//digitsStack.spacing = 8
|
||||||
|
|
||||||
mainStack.setArrangedSubviews([lettersStack, digitsStack])
|
let mainStack = UIStackView(arrangedSubviews: [lettersStack, digitsStack])
|
||||||
|
mainStack.spacing = 16
|
||||||
|
mainStack.distribution = .fillEqually
|
||||||
|
mainStack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
self.addSubview(mainStack)
|
||||||
|
|
||||||
lettersWidthConstraint = lettersStack.widthAnchor.constraint(equalToConstant: 0)
|
NSLayoutConstraint.activate([
|
||||||
digitsWidthConstraint = digitsStack.widthAnchor.constraint(equalToConstant: 0)
|
mainStack.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: insets.left),
|
||||||
|
mainStack.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -insets.right),
|
||||||
lettersWidthConstraint?.priority = .defaultLow
|
mainStack.topAnchor.constraint(equalTo: self.topAnchor, constant: insets.top),
|
||||||
digitsWidthConstraint?.priority = .defaultLow
|
mainStack.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: -insets.bottom)
|
||||||
|
])
|
||||||
NSLayoutConstraint.activate([lettersWidthConstraint, digitsWidthConstraint].compactMap { $0 })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func createLetterStack(_ views: [UIView]) -> UIStackView {
|
func createLetterStack(_ views: [UIView]) -> UIStackView {
|
||||||
|
|||||||
@ -403,5 +403,3 @@
|
|||||||
/* No comment provided by engineer. */
|
/* No comment provided by engineer. */
|
||||||
"ZIP (or OKTMO) code" = "Индекс (или ОКТМО)";
|
"ZIP (or OKTMO) code" = "Индекс (или ОКТМО)";
|
||||||
|
|
||||||
/* No comment provided by engineer. */
|
|
||||||
"Copy link to report" = "Копировать ссылку на отчет";
|
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
//
|
|
||||||
// Realm.swift
|
|
||||||
// AutoCatCore
|
|
||||||
//
|
|
||||||
// Created by Selim Mustafaev on 21.02.2023.
|
|
||||||
// Copyright © 2023 Selim Mustafaev. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import RealmSwift
|
|
||||||
|
|
||||||
extension Results {
|
|
||||||
|
|
||||||
public func toArray() -> [Element] {
|
|
||||||
Array(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension List {
|
|
||||||
|
|
||||||
public func toArray() -> [Element] {
|
|
||||||
Array(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -3,12 +3,12 @@ import RealmSwift
|
|||||||
|
|
||||||
public class AudioRecord: Object, Identifiable, Cloneable {
|
public class AudioRecord: Object, Identifiable, Cloneable {
|
||||||
|
|
||||||
@Persisted public var path: String = ""
|
@objc public dynamic var path: String = ""
|
||||||
@Persisted public var number: String?
|
@objc public dynamic var number: String?
|
||||||
@Persisted public var rawText: String = ""
|
@objc public dynamic var rawText: String = ""
|
||||||
@Persisted private var addedDate: TimeInterval = 0
|
@objc private dynamic var addedDate: TimeInterval = 0
|
||||||
@Persisted public var duration: TimeInterval = 0
|
@objc public dynamic var duration: TimeInterval = 0
|
||||||
@Persisted public var event: VehicleEvent?
|
@objc public dynamic var event: VehicleEvent?
|
||||||
|
|
||||||
public var identifier: TimeInterval = 0
|
public var identifier: TimeInterval = 0
|
||||||
public var id: TimeInterval {
|
public var id: TimeInterval {
|
||||||
@ -33,7 +33,7 @@ public class AudioRecord: Object, Identifiable, Cloneable {
|
|||||||
self.addedDate = Date().timeIntervalSince1970
|
self.addedDate = Date().timeIntervalSince1970
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,17 +8,17 @@ public enum DebugInfoStatus: Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class DebugInfo: Object, Decodable {
|
public class DebugInfo: Object, Decodable {
|
||||||
@Persisted public var autocod: DebugInfoEntry!
|
@objc public dynamic var autocod: DebugInfoEntry!
|
||||||
@Persisted public var vin01vin: DebugInfoEntry!
|
@objc public dynamic var vin01vin: DebugInfoEntry!
|
||||||
@Persisted public var vin01base: DebugInfoEntry!
|
@objc public dynamic var vin01base: DebugInfoEntry!
|
||||||
@Persisted public var vin01history: DebugInfoEntry!
|
@objc public dynamic var vin01history: DebugInfoEntry!
|
||||||
@Persisted public var nomerogram: DebugInfoEntry!
|
@objc public dynamic var nomerogram: DebugInfoEntry!
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DebugInfoEntry: Object, Decodable {
|
public class DebugInfoEntry: Object, Decodable {
|
||||||
@Persisted public var fields: Int64 = 0
|
@objc public dynamic var fields: Int64 = 0
|
||||||
@Persisted public var error: String?
|
@objc public dynamic var error: String?
|
||||||
@Persisted public var status: Int = 0
|
@objc public dynamic var status: Int = 0
|
||||||
|
|
||||||
public var statusEnum: DebugInfoStatus {
|
public var statusEnum: DebugInfoStatus {
|
||||||
get { DebugInfoStatus(rawValue: self.status)! }
|
get { DebugInfoStatus(rawValue: self.status)! }
|
||||||
|
|||||||
@ -38,29 +38,6 @@ public enum SortOrder: String, CustomStringConvertible, CaseIterable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SearchScope: Int, CaseIterable {
|
|
||||||
|
|
||||||
case plateNumber = 0
|
|
||||||
case vin = 1
|
|
||||||
case notes = 2
|
|
||||||
|
|
||||||
public var title: String {
|
|
||||||
switch self {
|
|
||||||
case .plateNumber: return NSLocalizedString("Plate number", comment: "")
|
|
||||||
case .vin: return NSLocalizedString("VIN", comment: "")
|
|
||||||
case .notes: return NSLocalizedString("Notes", comment: "")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var stringValue: String {
|
|
||||||
switch self {
|
|
||||||
case .plateNumber: return "plateNumber"
|
|
||||||
case .vin: return "vin"
|
|
||||||
case .notes: return "notes"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct Filter {
|
public struct Filter {
|
||||||
public var searchString = ""
|
public var searchString = ""
|
||||||
public var brand: String?
|
public var brand: String?
|
||||||
@ -78,7 +55,6 @@ public struct Filter {
|
|||||||
public var fromLocationDate: Date?
|
public var fromLocationDate: Date?
|
||||||
public var toLocationDate: Date?
|
public var toLocationDate: Date?
|
||||||
public var needReset: Bool = false
|
public var needReset: Bool = false
|
||||||
public var scope: SearchScope = .plateNumber
|
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
}
|
}
|
||||||
@ -98,7 +74,6 @@ public struct Filter {
|
|||||||
self.toDateUpdated = nil
|
self.toDateUpdated = nil
|
||||||
self.fromLocationDate = nil
|
self.fromLocationDate = nil
|
||||||
self.toLocationDate = nil
|
self.toLocationDate = nil
|
||||||
self.scope = .plateNumber
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func queryDictionary() -> [String: String] {
|
public func queryDictionary() -> [String: String] {
|
||||||
@ -147,8 +122,6 @@ public struct Filter {
|
|||||||
dict["toLocationDate"] = String(toLocationDate.timeIntervalSince1970)
|
dict["toLocationDate"] = String(toLocationDate.timeIntervalSince1970)
|
||||||
}
|
}
|
||||||
|
|
||||||
dict["scope"] = scope.stringValue
|
|
||||||
|
|
||||||
return dict
|
return dict
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,16 +2,16 @@ import Foundation
|
|||||||
import RealmSwift
|
import RealmSwift
|
||||||
|
|
||||||
public class Osago: Object, Decodable, Cloneable {
|
public class Osago: Object, Decodable, Cloneable {
|
||||||
@Persisted public var date: TimeInterval = 0
|
@objc public dynamic var date: TimeInterval = 0
|
||||||
@Persisted public var number: String = ""
|
@objc public dynamic var number: String = ""
|
||||||
@Persisted public var vin: String?
|
@objc public dynamic var vin: String?
|
||||||
@Persisted public var plateNumber: String?
|
@objc public dynamic var plateNumber: String?
|
||||||
@Persisted public var name: String = ""
|
@objc public dynamic var name: String = ""
|
||||||
@Persisted public var status: String = ""
|
@objc public dynamic var status: String = ""
|
||||||
@Persisted public var restrictions: String = ""
|
@objc public dynamic var restrictions: String = ""
|
||||||
@Persisted public var insurant: String?
|
@objc public dynamic var insurant: String?
|
||||||
@Persisted public var owner: String?
|
@objc public dynamic var owner: String?
|
||||||
@Persisted public var usageRegion: String?
|
@objc public dynamic var usageRegion: String?
|
||||||
|
|
||||||
public required init(copy: Osago) {
|
public required init(copy: Osago) {
|
||||||
self.date = copy.date
|
self.date = copy.date
|
||||||
@ -26,7 +26,7 @@ public class Osago: Object, Decodable, Cloneable {
|
|||||||
self.usageRegion = copy.usageRegion
|
self.usageRegion = copy.usageRegion
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,50 +2,50 @@ import Foundation
|
|||||||
import RealmSwift
|
import RealmSwift
|
||||||
|
|
||||||
public class VehicleName: Object, Decodable, Cloneable {
|
public class VehicleName: Object, Decodable, Cloneable {
|
||||||
@Persisted public var original: String?
|
@objc public dynamic var original: String?
|
||||||
@Persisted public var normalized: String?
|
@objc public dynamic var normalized: String?
|
||||||
|
|
||||||
public required init(copy: VehicleName) {
|
public required init(copy: VehicleName) {
|
||||||
self.original = copy.original
|
self.original = copy.original
|
||||||
self.normalized = copy.normalized
|
self.normalized = copy.normalized
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VehicleBrand: Object, Decodable, Cloneable {
|
public class VehicleBrand: Object, Decodable, Cloneable {
|
||||||
@Persisted public var name: VehicleName?
|
@objc public dynamic var name: VehicleName?
|
||||||
@Persisted public var logo: String?
|
@objc public dynamic var logo: String?
|
||||||
|
|
||||||
public required init(copy: VehicleBrand) {
|
public required init(copy: VehicleBrand) {
|
||||||
self.name = copy.name?.clone()
|
self.name = copy.name?.clone()
|
||||||
self.logo = copy.logo
|
self.logo = copy.logo
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VehicleModel: Object, Decodable, Cloneable {
|
public class VehicleModel: Object, Decodable, Cloneable {
|
||||||
@Persisted var name: VehicleName?
|
@objc dynamic var name: VehicleName?
|
||||||
|
|
||||||
public required init(copy: VehicleModel) {
|
public required init(copy: VehicleModel) {
|
||||||
self.name = copy.name?.clone()
|
self.name = copy.name?.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VehicleEngine: Object, Decodable, Cloneable {
|
public class VehicleEngine: Object, Decodable, Cloneable {
|
||||||
@Persisted public var number: String?
|
@objc public dynamic var number: String?
|
||||||
@Persisted public var volume: Int? = 0
|
public var volume: RealmOptional<Int> = RealmOptional(0)
|
||||||
@Persisted public var powerHp: Float? = 0
|
@objc public dynamic var powerHp: Float = 0
|
||||||
@Persisted public var powerKw: Float? = 0
|
public var powerKw: RealmOptional<Float> = RealmOptional(0)
|
||||||
@Persisted public var fuelType: String?
|
@objc public dynamic var fuelType: String?
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case number, volume, powerHp, powerKw, fuelType
|
case number, volume, powerHp, powerKw, fuelType
|
||||||
@ -54,13 +54,13 @@ public class VehicleEngine: Object, Decodable, Cloneable {
|
|||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
self.number = try container.decodeIfPresent(String.self, forKey: .number)
|
self.number = try container.decodeIfPresent(String.self, forKey: .number)
|
||||||
self.volume = try container.decodeIfPresent(Int.self, forKey: .volume)
|
self.volume = RealmOptional(try container.decodeIfPresent(Int.self, forKey: .volume))
|
||||||
self.powerHp = try container.decodeIfPresent(Float.self, forKey: .powerHp)
|
self.powerHp = try container.decode(Float.self, forKey: .powerHp)
|
||||||
self.powerKw = try container.decodeIfPresent(Float.self, forKey: .powerKw)
|
self.powerKw = RealmOptional(try container.decodeIfPresent(Float.self, forKey: .powerKw))
|
||||||
self.fuelType = try container.decodeIfPresent(String.self, forKey: .fuelType)
|
self.fuelType = try container.decodeIfPresent(String.self, forKey: .fuelType)
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,10 +74,10 @@ public class VehicleEngine: Object, Decodable, Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class VehiclePhoto: Object, Decodable, Cloneable {
|
public class VehiclePhoto: Object, Decodable, Cloneable {
|
||||||
@Persisted public var brand: String?
|
@objc public dynamic var brand: String?
|
||||||
@Persisted public var model: String?
|
@objc public dynamic var model: String?
|
||||||
@Persisted public var date: TimeInterval = 0
|
@objc public dynamic var date: TimeInterval = 0
|
||||||
@Persisted public var url: String = ""
|
@objc public dynamic var url: String = ""
|
||||||
|
|
||||||
public override var description: String {
|
public override var description: String {
|
||||||
let formatter = DateFormatter()
|
let formatter = DateFormatter()
|
||||||
@ -96,7 +96,7 @@ public class VehiclePhoto: Object, Decodable, Cloneable {
|
|||||||
self.url = copy.url
|
self.url = copy.url
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,17 +128,17 @@ public enum SteeringWheelPosition: CustomStringConvertible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class VehicleOwnershipPeriod: Object, Decodable, Cloneable {
|
public class VehicleOwnershipPeriod: Object, Decodable, Cloneable {
|
||||||
@Persisted public var lastOperation: String = ""
|
@objc public dynamic var lastOperation: String = ""
|
||||||
@Persisted public var ownerType: String = ""
|
@objc public dynamic var ownerType: String = ""
|
||||||
@Persisted public var from: Int64 = 0
|
@objc public dynamic var from: Int64 = 0
|
||||||
@Persisted public var to: Int64 = 0
|
@objc public dynamic var to: Int64 = 0
|
||||||
@Persisted public var region: String?
|
@objc public dynamic var region: String?
|
||||||
@Persisted public var registrationRegion: String?
|
@objc public dynamic var registrationRegion: String?
|
||||||
@Persisted public var locality: String?
|
@objc public dynamic var locality: String?
|
||||||
@Persisted public var code: String?
|
@objc public dynamic var code: String?
|
||||||
@Persisted public var street: String?
|
@objc public dynamic var street: String?
|
||||||
@Persisted public var building: String?
|
@objc public dynamic var building: String?
|
||||||
@Persisted public var inn: String?
|
@objc public dynamic var inn: String?
|
||||||
|
|
||||||
required public init(copy: VehicleOwnershipPeriod) {
|
required public init(copy: VehicleOwnershipPeriod) {
|
||||||
self.lastOperation = copy.lastOperation
|
self.lastOperation = copy.lastOperation
|
||||||
@ -154,37 +154,37 @@ public class VehicleOwnershipPeriod: Object, Decodable, Cloneable {
|
|||||||
self.inn = copy.inn
|
self.inn = copy.inn
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportable {
|
public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportable {
|
||||||
@Persisted public var brand: VehicleBrand?
|
@objc public dynamic var brand: VehicleBrand?
|
||||||
@Persisted public var model: VehicleModel?
|
@objc public dynamic var model: VehicleModel?
|
||||||
@Persisted public var color: String?
|
@objc public dynamic var color: String?
|
||||||
@Persisted public var year: Int = 0
|
@objc public dynamic var year: Int = 0
|
||||||
@Persisted public var category: String?
|
@objc public dynamic var category: String?
|
||||||
@Persisted public var engine: VehicleEngine?
|
@objc public dynamic var engine: VehicleEngine?
|
||||||
@Persisted private var number: String = ""
|
@objc private dynamic var number: String = ""
|
||||||
@Persisted public var currentNumber: String?
|
@objc public dynamic var currentNumber: String?
|
||||||
@Persisted public var vin1: String?
|
@objc public dynamic var vin1: String?
|
||||||
@Persisted public var vin2: String?
|
@objc public dynamic var vin2: String?
|
||||||
@Persisted public var sts: String?
|
@objc public dynamic var sts: String?
|
||||||
@Persisted public var pts: String?
|
@objc public dynamic var pts: String?
|
||||||
@Persisted public var isRightWheel: Bool?
|
public var isRightWheel = RealmOptional<Bool>()
|
||||||
@Persisted public var isJapanese: Bool?
|
public var isJapanese: RealmOptional<Bool> = RealmOptional<Bool>()
|
||||||
@Persisted public var addedDate: TimeInterval = 0
|
@objc public dynamic var addedDate: TimeInterval = 0
|
||||||
@Persisted public var updatedDate: TimeInterval = 0
|
@objc public dynamic var updatedDate: TimeInterval = 0
|
||||||
@Persisted public var addedBy: String = ""
|
@objc public dynamic var addedBy: String = ""
|
||||||
@Persisted public var photos: List<VehiclePhoto>
|
public var photos = List<VehiclePhoto>()
|
||||||
@Persisted public var ownershipPeriods: List<VehicleOwnershipPeriod>
|
public var ownershipPeriods = List<VehicleOwnershipPeriod>()
|
||||||
@Persisted public var events: List<VehicleEvent>
|
public var events = List<VehicleEvent>()
|
||||||
@Persisted public var osagoContracts: List<Osago>
|
public var osagoContracts = List<Osago>()
|
||||||
@Persisted public var ads: List<VehicleAd>
|
public var ads = List<VehicleAd>()
|
||||||
@Persisted public var notes: List<VehicleNote>
|
public var notes = List<VehicleNote>()
|
||||||
@Persisted public var debugInfo: DebugInfo?
|
@objc public dynamic var debugInfo: DebugInfo?
|
||||||
@Persisted public var synchronized: Bool = true
|
@objc public dynamic var synchronized: Bool = true
|
||||||
|
|
||||||
lazy var formatter: DateFormatter = {
|
lazy var formatter: DateFormatter = {
|
||||||
let f = DateFormatter()
|
let f = DateFormatter()
|
||||||
@ -221,8 +221,6 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
|||||||
}
|
}
|
||||||
|
|
||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
super.init()
|
|
||||||
|
|
||||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
self.brand = try container.decodeIfPresent(VehicleBrand.self, forKey: .brand)
|
self.brand = try container.decodeIfPresent(VehicleBrand.self, forKey: .brand)
|
||||||
self.model = try container.decodeIfPresent(VehicleModel.self, forKey: .model)
|
self.model = try container.decodeIfPresent(VehicleModel.self, forKey: .model)
|
||||||
@ -236,8 +234,8 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
|||||||
self.vin2 = try container.decodeIfPresent(String.self, forKey: .vin2)
|
self.vin2 = try container.decodeIfPresent(String.self, forKey: .vin2)
|
||||||
self.sts = try container.decodeIfPresent(String.self, forKey: .sts)
|
self.sts = try container.decodeIfPresent(String.self, forKey: .sts)
|
||||||
self.pts = try container.decodeIfPresent(String.self, forKey: .pts)
|
self.pts = try container.decodeIfPresent(String.self, forKey: .pts)
|
||||||
self.isRightWheel = try container.decodeIfPresent(Bool.self, forKey: .isRightWheel)
|
self.isRightWheel = RealmOptional(try container.decodeIfPresent(Bool.self, forKey: .isRightWheel))
|
||||||
self.isJapanese = try container.decodeIfPresent(Bool.self, forKey: .isJapanese)
|
self.isJapanese = RealmOptional(try container.decodeIfPresent(Bool.self, forKey: .isJapanese))
|
||||||
self.addedDate = (try container.decode(TimeInterval.self, forKey: .addedDate))/1000
|
self.addedDate = (try container.decode(TimeInterval.self, forKey: .addedDate))/1000
|
||||||
self.addedBy = try container.decode(String.self, forKey: .addedBy)
|
self.addedBy = try container.decode(String.self, forKey: .addedBy)
|
||||||
self.debugInfo = try container.decodeIfPresent(DebugInfo.self, forKey: .debugInfo)
|
self.debugInfo = try container.decodeIfPresent(DebugInfo.self, forKey: .debugInfo)
|
||||||
@ -271,12 +269,11 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
|||||||
self.synchronized = true
|
self.synchronized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(_ number: String) {
|
public init(_ number: String) {
|
||||||
super.init()
|
|
||||||
self.number = number
|
self.number = number
|
||||||
self.addedDate = Date().timeIntervalSince1970
|
self.addedDate = Date().timeIntervalSince1970
|
||||||
self.updatedDate = self.addedDate
|
self.updatedDate = self.addedDate
|
||||||
@ -378,7 +375,7 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
|||||||
// MARK: - Exportable
|
// MARK: - Exportable
|
||||||
|
|
||||||
public static var csvHeader: String {
|
public static var csvHeader: String {
|
||||||
return "Plate Number, Model, Color, Year, Power (HP), Events, Owners, VIN, STS, PTS, Engine number, Added Date, Updated date, Locations, Notes"
|
return "Plate Number, Model, Color, Year, Power (HP), Events, Owners, VIN, STS, PTS, Added Date, Updated date, Locations, Notes"
|
||||||
}
|
}
|
||||||
|
|
||||||
public var csvLine: String {
|
public var csvLine: String {
|
||||||
@ -399,7 +396,7 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
|||||||
|
|
||||||
let number = self.currentNumber == nil ? self.number : "\(self.number) (\(self.currentNumber ?? ""))"
|
let number = self.currentNumber == nil ? self.number : "\(self.number) (\(self.currentNumber ?? ""))"
|
||||||
|
|
||||||
return String(format: "%@, \"%@\", %@, %d, %f, %d, %d, %@, %@, %@, %@, \"%@\", \"%@\", \"%@\", \"%@\"",
|
return String(format: "%@, \"%@\", %@, %d, %f, %d, %d, %@, %@, %@, \"%@\", \"%@\", \"%@\", \"%@\"",
|
||||||
number,
|
number,
|
||||||
model,
|
model,
|
||||||
self.color ?? "",
|
self.color ?? "",
|
||||||
@ -410,7 +407,6 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
|||||||
self.vin1 ?? "",
|
self.vin1 ?? "",
|
||||||
self.sts ?? "",
|
self.sts ?? "",
|
||||||
self.pts ?? "",
|
self.pts ?? "",
|
||||||
self.engine?.number ?? "",
|
|
||||||
added,
|
added,
|
||||||
updated,
|
updated,
|
||||||
eventsString,
|
eventsString,
|
||||||
|
|||||||
@ -2,15 +2,15 @@ import Foundation
|
|||||||
import RealmSwift
|
import RealmSwift
|
||||||
|
|
||||||
public class VehicleAd: Object, Decodable, Cloneable {
|
public class VehicleAd: Object, Decodable, Cloneable {
|
||||||
@Persisted public var id: Int = 0
|
@objc public dynamic var id: Int = 0
|
||||||
@Persisted public var url: String?
|
@objc public dynamic var url: String?
|
||||||
@Persisted public var price: String?
|
@objc public dynamic var price: String?
|
||||||
@Persisted public var date: TimeInterval = Date().timeIntervalSince1970
|
@objc public dynamic var date: TimeInterval = Date().timeIntervalSince1970
|
||||||
@Persisted public var mileage: String?
|
@objc public dynamic var mileage: String?
|
||||||
@Persisted public var region: String?
|
@objc public dynamic var region: String?
|
||||||
@Persisted public var city: String?
|
@objc public dynamic var city: String?
|
||||||
@Persisted public var adDescription: String?
|
@objc public dynamic var adDescription: String?
|
||||||
@Persisted public var photos: List<String>
|
public var photos = List<String>()
|
||||||
|
|
||||||
public required init(copy: VehicleAd) {
|
public required init(copy: VehicleAd) {
|
||||||
self.id = copy.id
|
self.id = copy.id
|
||||||
@ -27,7 +27,7 @@ public class VehicleAd: Object, Decodable, Cloneable {
|
|||||||
self.photos = photos
|
self.photos = photos
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,12 +4,12 @@ import RxSwift
|
|||||||
import CoreLocation
|
import CoreLocation
|
||||||
|
|
||||||
public class VehicleEvent: Object, Codable, Cloneable {
|
public class VehicleEvent: Object, Codable, Cloneable {
|
||||||
@Persisted public var id: String = UUID().uuidString
|
@objc public dynamic var id: String = UUID().uuidString
|
||||||
@Persisted public var date: TimeInterval = Date().timeIntervalSince1970
|
@objc public dynamic var date: TimeInterval = Date().timeIntervalSince1970
|
||||||
@Persisted public var latitude: Double = 0
|
@objc public dynamic var latitude: Double = 0
|
||||||
@Persisted public var longitude: Double = 0
|
@objc public dynamic var longitude: Double = 0
|
||||||
@Persisted public var address: String? = nil
|
@objc public dynamic var address: String? = nil
|
||||||
@Persisted public var addedBy: String? = nil
|
@objc public dynamic var addedBy: String? = nil
|
||||||
|
|
||||||
public var number: String?
|
public var number: String?
|
||||||
public var coordinate: CLLocationCoordinate2D {
|
public var coordinate: CLLocationCoordinate2D {
|
||||||
@ -22,7 +22,7 @@ public class VehicleEvent: Object, Codable, Cloneable {
|
|||||||
self.addedBy = Settings.shared.user.email
|
self.addedBy = Settings.shared.user.email
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,20 +78,4 @@ public class VehicleEvent: Object, Codable, Cloneable {
|
|||||||
self.number = copy.number
|
self.number = copy.number
|
||||||
self.addedBy = copy.addedBy
|
self.addedBy = copy.addedBy
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Codable
|
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
|
||||||
case id, date, latitude, longitude, address, addedBy
|
|
||||||
}
|
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
||||||
try container.encode(id, forKey: .id)
|
|
||||||
try container.encode(date, forKey: .date)
|
|
||||||
try container.encode(latitude, forKey: .latitude)
|
|
||||||
try container.encode(longitude, forKey: .longitude)
|
|
||||||
try container.encodeIfPresent(address, forKey: .address)
|
|
||||||
try container.encodeIfPresent(addedBy, forKey: .addedBy)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,10 @@ import Foundation
|
|||||||
import RealmSwift
|
import RealmSwift
|
||||||
|
|
||||||
public class VehicleNote: Object, Codable, Cloneable {
|
public class VehicleNote: Object, Codable, Cloneable {
|
||||||
@Persisted public var id: String = UUID().uuidString
|
@objc public dynamic var id: String = UUID().uuidString
|
||||||
@Persisted public var user: String = ""
|
@objc public dynamic var user: String = ""
|
||||||
@Persisted public var date: TimeInterval = Date().timeIntervalSince1970
|
@objc public dynamic var date: TimeInterval = Date().timeIntervalSince1970
|
||||||
@Persisted public var text: String = ""
|
@objc public dynamic var text: String = ""
|
||||||
|
|
||||||
// MARK: - Cloneable
|
// MARK: - Cloneable
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ public class VehicleNote: Object, Codable, Cloneable {
|
|||||||
self.text = copy.text
|
self.text = copy.text
|
||||||
}
|
}
|
||||||
|
|
||||||
required override init() {
|
required init() {
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -46,7 +46,7 @@ public class Api {
|
|||||||
return Single.error(self.genError("Error creating request", suggestion: ""))
|
return Single.error(self.genError("Error creating request", suggestion: ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.session.rx.response(request: request).asSingle().map { httpResp, data in
|
return self.session.rx.data(request: request).asSingle().map { data in
|
||||||
// let str = String(data: data, encoding: .utf8)
|
// let str = String(data: data, encoding: .utf8)
|
||||||
// print("================================")
|
// print("================================")
|
||||||
// if let string = str?.replacingOccurrences(of: "\\\"", with: "\"")
|
// if let string = str?.replacingOccurrences(of: "\\\"", with: "\"")
|
||||||
@ -55,15 +55,6 @@ public class Api {
|
|||||||
// print(string)
|
// print(string)
|
||||||
// }
|
// }
|
||||||
// print("================================")
|
// print("================================")
|
||||||
|
|
||||||
if httpResp.statusCode == 401 {
|
|
||||||
throw genError("Unauthorized", suggestion: "", code: httpResp.statusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
if httpResp.statusCode < 200 || httpResp.statusCode >= 300 {
|
|
||||||
throw genError("HTTP error \(httpResp.statusCode)", suggestion: "", code: httpResp.statusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
let resp = try JSONDecoder().decode(Response<T>.self, from: data)
|
let resp = try JSONDecoder().decode(Response<T>.self, from: data)
|
||||||
if resp.success {
|
if resp.success {
|
||||||
@ -172,7 +163,7 @@ public class Api {
|
|||||||
Settings.shared.user.firebaseRefreshToken = newRefreshToken
|
Settings.shared.user.firebaseRefreshToken = newRefreshToken
|
||||||
print("Refresh token: \(newRefreshToken)")
|
print("Refresh token: \(newRefreshToken)")
|
||||||
}
|
}
|
||||||
}.catch { err in
|
}.catchError { err in
|
||||||
print(err)
|
print(err)
|
||||||
return .just(())
|
return .just(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,10 +15,6 @@ public enum Constants {
|
|||||||
"А": "A", "В": "B", "Е": "E", "К": "K", "М": "M", "Н": "H", "О": "O", "Р": "P", "С": "C", "Т": "T", "У": "Y", "Х": "X"
|
"А": "A", "В": "B", "Е": "E", "К": "K", "М": "M", "Н": "H", "О": "O", "Р": "P", "С": "C", "Т": "T", "У": "Y", "Х": "X"
|
||||||
]
|
]
|
||||||
|
|
||||||
public static let vinLetters: [Character] = [
|
|
||||||
"A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"
|
|
||||||
]
|
|
||||||
|
|
||||||
public static let googleAuthURL = "https://accounts.google.com/o/oauth2/v2/auth"
|
public static let googleAuthURL = "https://accounts.google.com/o/oauth2/v2/auth"
|
||||||
public static let googleTokenURL = "https://oauth2.googleapis.com/token"
|
public static let googleTokenURL = "https://oauth2.googleapis.com/token"
|
||||||
public static let googleRedirectURL = "com.googleusercontent.apps.994679674451-k7clunkk4nicl6iuajdtc5u7hvustbdb:/oauth2callback"
|
public static let googleRedirectURL = "com.googleusercontent.apps.994679674451-k7clunkk4nicl6iuajdtc5u7hvustbdb:/oauth2callback"
|
||||||
|
|||||||
@ -89,14 +89,14 @@ public class RxLocationManager {
|
|||||||
if let status = result, [.authorizedWhenInUse, .authorizedAlways].contains(status) {
|
if let status = result, [.authorizedWhenInUse, .authorizedAlways].contains(status) {
|
||||||
observer(.success(()))
|
observer(.success(()))
|
||||||
} else {
|
} else {
|
||||||
observer(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Location permission error"])))
|
observer(.error(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Location permission error"])))
|
||||||
}
|
}
|
||||||
}, onFailure: { observer(.failure($0)) })
|
}, onError: { observer(.error($0)) })
|
||||||
case .denied:
|
case .denied:
|
||||||
observer(.failure(CLError(.denied)))
|
observer(.error(CLError(.denied)))
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
observer(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Location permission error"])))
|
observer(.error(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Location permission error"])))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,11 +139,11 @@ public class RxLocationManager {
|
|||||||
let location = CLLocation(latitude: latitude, longitude: longitude)
|
let location = CLLocation(latitude: latitude, longitude: longitude)
|
||||||
geocoder.reverseGeocodeLocation(location) { placemarks, error in
|
geocoder.reverseGeocodeLocation(location) { placemarks, error in
|
||||||
if let error = error {
|
if let error = error {
|
||||||
observer(.failure(error))
|
observer(.error(error))
|
||||||
} else if let placemark = placemarks?.first, let name = placemark.name {
|
} else if let placemark = placemarks?.first, let name = placemark.name {
|
||||||
observer(.success(name))
|
observer(.success(name))
|
||||||
} else {
|
} else {
|
||||||
observer(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Reverse geolocation error"])))
|
observer(.error(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Reverse geolocation error"])))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user