Compare commits
No commits in common. "771b5923b61ecb72cc9176628d9bb6c054f82b00" and "df43b9ff7fd9a1a4319b1d14e1110ee0f28a245a" have entirely different histories.
771b5923b6
...
df43b9ff7f
@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 52;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
@ -25,15 +25,6 @@
|
||||
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471523FDEB2A00B424AF /* MainSplitController.swift */; };
|
||||
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11471723FDEBFA00B424AF /* ReportController.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 */; };
|
||||
7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A21112924FC3D7E003BBF6F /* AudioEngine.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 */; };
|
||||
7A99406426E4BFAE002E9CB6 /* VehicleNoteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A99406326E4BFAE002E9CB6 /* VehicleNoteCell.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 */; };
|
||||
7AA7BC3525A5DFB80053A5D5 /* ExceptionCatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */; };
|
||||
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */ = {isa = PBXBuildFile; productRef = 7AABDE1C2532F3EB0041AFC6 /* PKHUD */; };
|
||||
@ -134,6 +128,8 @@
|
||||
7AF6D21F2677C1680086EA64 /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474823FF2B2D00B424AF /* Response.swift */; };
|
||||
7AF6D2202677C1680086EA64 /* Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A333813249A532400D878F1 /* Filter.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 */; };
|
||||
7AF6D22A2677C3AD0086EA64 /* Exportable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE8424D26109F78002F6B31 /* Exportable.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -200,9 +196,6 @@
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -330,13 +323,12 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
7A1CF80C29A41D58007962DA /* RxRelay in Frameworks */,
|
||||
7A1CF80529A41C66007962DA /* RealmSwift in Frameworks */,
|
||||
7A1CF80829A41D58007962DA /* RxBlocking in Frameworks */,
|
||||
7A1CF80A29A41D58007962DA /* RxCocoa in Frameworks */,
|
||||
7A1CF80329A41C62007962DA /* Realm in Frameworks */,
|
||||
7AA54C1E26CD977A00F2BF28 /* RxSwift in Frameworks */,
|
||||
7AF6D2252677C2B40086EA64 /* RealmSwift in Frameworks */,
|
||||
7AA54C1C26CD977A00F2BF28 /* RxCocoa in Frameworks */,
|
||||
7AF6D2232677C2B40086EA64 /* Realm in Frameworks */,
|
||||
7AABB1F2267E9CC800D7AB32 /* SwiftDate in Frameworks */,
|
||||
7A1CF80E29A41D58007962DA /* RxSwift in Frameworks */,
|
||||
7AA54C2026CD977A00F2BF28 /* RxRealm in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -615,8 +607,6 @@
|
||||
7AC355582969746600889457 /* UIControl.swift */,
|
||||
7AC3555A296995B200889457 /* UIEdgeInsets.swift */,
|
||||
7A91894E29A2BD8700519C74 /* GestureRecognizers.swift */,
|
||||
7A17CE492A2E820300626A6E /* UIStackView.swift */,
|
||||
7A17CE4B2A2E850200626A6E /* UISegmentedControl.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@ -669,7 +659,6 @@
|
||||
children = (
|
||||
7A27ADF824A09CAD0035F39E /* CocoaError.swift */,
|
||||
7AE8424D26109F78002F6B31 /* Exportable.swift */,
|
||||
7A1CF81529A42117007962DA /* Realm.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@ -746,13 +735,12 @@
|
||||
);
|
||||
name = AutoCatCore;
|
||||
packageProductDependencies = (
|
||||
7AF6D2222677C2B40086EA64 /* Realm */,
|
||||
7AF6D2242677C2B40086EA64 /* RealmSwift */,
|
||||
7AABB1F1267E9CC800D7AB32 /* SwiftDate */,
|
||||
7A1CF80229A41C62007962DA /* Realm */,
|
||||
7A1CF80429A41C66007962DA /* RealmSwift */,
|
||||
7A1CF80729A41D58007962DA /* RxBlocking */,
|
||||
7A1CF80929A41D58007962DA /* RxCocoa */,
|
||||
7A1CF80B29A41D58007962DA /* RxRelay */,
|
||||
7A1CF80D29A41D58007962DA /* RxSwift */,
|
||||
7AA54C1B26CD977A00F2BF28 /* RxCocoa */,
|
||||
7AA54C1D26CD977A00F2BF28 /* RxSwift */,
|
||||
7AA54C1F26CD977A00F2BF28 /* RxRealm */,
|
||||
);
|
||||
productName = AutoCatCore;
|
||||
productReference = 7AF6D1EF2677C03B0086EA64 /* AutoCatCore.framework */;
|
||||
@ -791,14 +779,15 @@
|
||||
);
|
||||
mainGroup = 7A1146F423FDE7E500B424AF;
|
||||
packageReferences = (
|
||||
7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */,
|
||||
7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */,
|
||||
7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */,
|
||||
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||
7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */,
|
||||
7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */,
|
||||
7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */,
|
||||
7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */,
|
||||
7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */,
|
||||
7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */,
|
||||
7A1CF80629A41D58007962DA /* XCRemoteSwiftPackageReference "RxSwift" */,
|
||||
);
|
||||
productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */;
|
||||
projectDirPath = "";
|
||||
@ -871,7 +860,6 @@
|
||||
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */,
|
||||
7A0420B62568650C00034941 /* DkbmController.swift in Sources */,
|
||||
7A27ADF5249FD2F90035F39E /* FileManagerExt.swift in Sources */,
|
||||
7A17CE4A2A2E820300626A6E /* UIStackView.swift in Sources */,
|
||||
7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */,
|
||||
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */,
|
||||
7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */,
|
||||
@ -923,7 +911,6 @@
|
||||
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
|
||||
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
|
||||
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
|
||||
7A17CE4C2A2E850200626A6E /* UISegmentedControl.swift in Sources */,
|
||||
6841A85D4B60DB71D1E68DA0 /* ImageGrid.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -960,7 +947,6 @@
|
||||
7A0B663729984201006F5189 /* DateCache.swift in Sources */,
|
||||
7AF6D21D2677C1680086EA64 /* Osago.swift in Sources */,
|
||||
7AF6D2152677C1680086EA64 /* Settings.swift in Sources */,
|
||||
7A1CF81629A42117007962DA /* Realm.swift in Sources */,
|
||||
7A761C052677F1BC0005F28F /* CocoaError.swift in Sources */,
|
||||
7AF6D2132677C15A0086EA64 /* AudioRecord.swift in Sources */,
|
||||
7AF6D21B2677C1680086EA64 /* Vehicle.swift in Sources */,
|
||||
@ -1158,18 +1144,15 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 117;
|
||||
CURRENT_PROJECT_VERSION = 111;
|
||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
@ -1186,18 +1169,15 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 117;
|
||||
CURRENT_PROJECT_VERSION = 111;
|
||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = AutoCat;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.utilities";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
"IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = pro.aliencat.AutoCat;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
@ -1357,20 +1337,20 @@
|
||||
minimumVersion = 6.1.0;
|
||||
};
|
||||
};
|
||||
7A1CF7FD29A41C2F007962DA /* XCRemoteSwiftPackageReference "realm-swift" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/realm/realm-swift.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 10.36.0;
|
||||
};
|
||||
};
|
||||
7A1CF80629A41D58007962DA /* XCRemoteSwiftPackageReference "RxSwift" */ = {
|
||||
7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/ReactiveX/RxSwift.git";
|
||||
requirement = {
|
||||
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" */ = {
|
||||
@ -1381,6 +1361,14 @@
|
||||
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" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/sindresorhus/ExceptionCatcher";
|
||||
@ -1416,36 +1404,6 @@
|
||||
/* End XCRemoteSwiftPackageReference 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 */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */;
|
||||
@ -1456,6 +1414,21 @@
|
||||
package = 7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "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 */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */;
|
||||
@ -1476,6 +1449,16 @@
|
||||
package = 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "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 */
|
||||
};
|
||||
rootObject = 7A1146F523FDE7E500B424AF /* Project object */;
|
||||
|
||||
@ -37,21 +37,30 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "realm-core",
|
||||
"identity" : "realm-cocoa",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/realm/realm-core.git",
|
||||
"location" : "https://github.com/realm/realm-cocoa",
|
||||
"state" : {
|
||||
"revision" : "dd91f5f967c4ae89c37e24ab2a0315c31106648f",
|
||||
"version" : "13.6.0"
|
||||
"revision" : "2dce752b48c3265c63ab04a8c66ddfdf9185f847",
|
||||
"version" : "5.5.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "realm-swift",
|
||||
"identity" : "realm-core",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/realm/realm-swift.git",
|
||||
"location" : "https://github.com/realm/realm-core",
|
||||
"state" : {
|
||||
"revision" : "8ac6fe1aa5d0fb0100062d80863416a4d70de8ca",
|
||||
"version" : "10.37.0"
|
||||
"revision" : "66d79b3c5213fb14d491c1b22193077b488d49a6",
|
||||
"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",
|
||||
"location" : "https://github.com/ReactiveX/RxSwift.git",
|
||||
"state" : {
|
||||
"revision" : "b4307ba0b6425c0ba4178e138799946c3da594f8",
|
||||
"version" : "6.5.0"
|
||||
"revision" : "254617dd7fae0c45319ba5fbea435bf4d0e15b5d",
|
||||
"version" : "5.1.2"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.SymbolicBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "676638C8-1CC5-4C04-98B0-1C0D6CB28B76"
|
||||
shouldBeEnabled = "No"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
symbolName = "UITableViewAlertForLayoutOutsideViewHierarchy"
|
||||
@ -27,68 +27,5 @@
|
||||
</Locations>
|
||||
</BreakpointContent>
|
||||
</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>
|
||||
</Bucket>
|
||||
|
||||
@ -15,13 +15,6 @@ extension UISearchController {
|
||||
searchController.obscuresBackgroundDuringPresentation = false
|
||||
searchController.hidesNavigationBarDuringPresentation = false
|
||||
searchController.searchBar.keyboardType = .webSearch
|
||||
|
||||
if #available(iOS 16, *) {
|
||||
searchController.scopeBarActivation = .onTextEntry
|
||||
} else {
|
||||
searchController.automaticallyShowsScopeBar = true
|
||||
}
|
||||
|
||||
return searchController
|
||||
}
|
||||
|
||||
@ -44,14 +37,4 @@ extension UISearchController {
|
||||
searchBar.smartInsertDeleteType = .no
|
||||
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 {
|
||||
|
||||
let config = Realm.Configuration(
|
||||
schemaVersion: 40,
|
||||
schemaVersion: 38,
|
||||
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 {
|
||||
migration.enumerateObjects(ofType: "Vehicle") { old, new in
|
||||
if let oldDebugInfo = old?["debugInfo"] as? DynamicObject, let newDebugInfo = new?["debugInfo"] as? DynamicObject {
|
||||
|
||||
@ -173,17 +173,17 @@
|
||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||
<prototypes>
|
||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="EventCell" id="QIb-Hv-tvk" customClass="EventCell" customModule="AutoCat" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="50" width="375" height="432"/>
|
||||
<rect key="frame" x="0.0" y="50" width="375" height="431.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QIb-Hv-tvk" id="Ypt-ch-fGT">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="432"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="431.5"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HP8-oO-yhP">
|
||||
<rect key="frame" x="16" y="8" width="343" height="416"/>
|
||||
<rect key="frame" x="16" y="8" width="343" height="415.5"/>
|
||||
<subviews>
|
||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="k4Z-KM-byE">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="416"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="415.5"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xcQ-Wz-gJ0">
|
||||
<rect key="frame" x="0.0" y="0.0" width="335" height="201"/>
|
||||
@ -192,7 +192,7 @@
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1tQ-zM-6T9">
|
||||
<rect key="frame" x="0.0" y="209" width="335" height="207"/>
|
||||
<rect key="frame" x="0.0" y="209" width="335" height="206.5"/>
|
||||
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
|
||||
<color key="textColor" systemColor="secondaryLabelColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
@ -200,7 +200,7 @@
|
||||
</subviews>
|
||||
</stackView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="750" verticalHuggingPriority="251" image="person" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="CFI-xa-eLs">
|
||||
<rect key="frame" x="343" y="1.5" width="0.0" height="413.5"/>
|
||||
<rect key="frame" x="343" y="1.5" width="0.0" height="413"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
</stackView>
|
||||
|
||||
@ -65,7 +65,7 @@ class AuthController: UIViewController, ASAuthorizationControllerDelegate, ASAut
|
||||
authorizationController.performRequests()
|
||||
}
|
||||
|
||||
func goToMainScreen(user: AutoCatCore.User) {
|
||||
func goToMainScreen(user: User) {
|
||||
guard let realm = try? Realm() else {
|
||||
HUD.flash(.labeledError(title: nil, subtitle: "Database error"))
|
||||
return
|
||||
|
||||
@ -2,6 +2,7 @@ import UIKit
|
||||
import RealmSwift
|
||||
import RxSwift
|
||||
import SwiftDate
|
||||
import RxRealm
|
||||
import PKHUD
|
||||
import CoreLocation
|
||||
import AutoCatCore
|
||||
@ -99,7 +100,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
||||
}
|
||||
HUD.hide()
|
||||
self.showErrors(errors)
|
||||
} onFailure: { error in
|
||||
} onError: { error in
|
||||
HUD.hide()
|
||||
self.show(error: error)
|
||||
//HUD.show(error: error)
|
||||
@ -137,12 +138,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
||||
let csvString = try self.historyDataSource.makeCsv()
|
||||
let tmpUrl = FileManager.default.tmpUrl(name: "history", ext: "csv")
|
||||
try csvString.write(to: tmpUrl, atomically: true, encoding: .utf8)
|
||||
|
||||
#if targetEnvironment(macCatalyst)
|
||||
self.save(file: tmpUrl)
|
||||
#else
|
||||
self.shareFile(tmpUrl)
|
||||
#endif
|
||||
} catch {
|
||||
self.show(error: error)
|
||||
}
|
||||
@ -203,16 +199,6 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
||||
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
|
||||
|
||||
func checkTapped(number: String) {
|
||||
@ -235,7 +221,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
||||
}
|
||||
HUD.hide()
|
||||
self.showErrors(errors)
|
||||
} onFailure: { error in
|
||||
} onError: { error in
|
||||
HUD.hide()
|
||||
self.show(error: error)
|
||||
}
|
||||
@ -338,7 +324,7 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
||||
}
|
||||
HUD.hide()
|
||||
self.showErrors(errors)
|
||||
} onFailure: { error in
|
||||
} onError: { error in
|
||||
HUD.hide()
|
||||
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))
|
||||
if action != .doNotSend {
|
||||
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) }
|
||||
.observe(on: MainScheduler.instance)
|
||||
.catch { .just((event: nil, error: $0)) }
|
||||
.observeOn(MainScheduler.instance)
|
||||
.catchError { .just((event: nil, error: $0)) }
|
||||
}
|
||||
|
||||
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
|
||||
try self.save(vehicle: vehicle)
|
||||
return (vehicle: vehicle, error: nil)
|
||||
}
|
||||
.catch { error in
|
||||
.catchError { error in
|
||||
let realm = try Realm()
|
||||
if let existingVehicle = realm.object(ofType: Vehicle.self, forPrimaryKey: number) {
|
||||
return .just((vehicle: existingVehicle, error: error))
|
||||
@ -433,12 +419,12 @@ class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpd
|
||||
} else {
|
||||
if let event = eventResult.event {
|
||||
return Api.add(event: event, to: vehicleResult.vehicle.getNumber())
|
||||
.observe(on: MainScheduler.instance)
|
||||
.observeOn(MainScheduler.instance)
|
||||
.map {
|
||||
try self.save(vehicle: $0)
|
||||
return (vehicle: $0, errors: errors)
|
||||
}
|
||||
.catch { error in
|
||||
.catchError { error in
|
||||
errors.append(error)
|
||||
return .just((vehicle: vehicleResult.vehicle, errors: errors))
|
||||
}
|
||||
|
||||
@ -145,77 +145,42 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
// MARK: - UITableViewDelegate
|
||||
|
||||
func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||
guard let vehicle = self.vehicle else {
|
||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||
return nil
|
||||
}
|
||||
|
||||
let event = vehicle.events[indexPath.row]
|
||||
|
||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
|
||||
|
||||
let copy = UIAction(title: NSLocalizedString("Copy", comment: ""),
|
||||
image: UIImage(systemName: "doc.on.doc"),
|
||||
handler: { _ in self.copyEvent(event: event) })
|
||||
|
||||
let share = UIAction(title: NSLocalizedString("Share", comment: ""),
|
||||
image: UIImage(systemName: "square.and.arrow.up"),
|
||||
handler: { _ in self.shareEvent(event: event) })
|
||||
|
||||
let edit = UIAction(title: NSLocalizedString("Edit", comment: ""),
|
||||
image: UIImage(systemName: "pencil"),
|
||||
handler: { _ in self.editEvent(event: event) })
|
||||
|
||||
let delete = UIAction(title: NSLocalizedString("Delete", comment: ""),
|
||||
image: UIImage(systemName: "trash"),
|
||||
attributes: .destructive,
|
||||
handler: { _ in self.deleteEvent(event: event) })
|
||||
|
||||
let openApple = UIAction(title: NSLocalizedString("Apple Maps", comment: ""),
|
||||
image: UIImage(systemName: "map"),
|
||||
handler: { _ in self.openInAppleMaps(event: event) })
|
||||
|
||||
let openYandex = UIAction(title: NSLocalizedString("Yandex Maps", comment: ""),
|
||||
image: UIImage(systemName: "map"),
|
||||
handler: { _ in self.openInYandexMaps(event: event) })
|
||||
|
||||
let openMenu: UIMenuElement
|
||||
if let yandexUrl = URL(string: "yandexmaps://"),
|
||||
UIApplication.shared.canOpenURL(yandexUrl)
|
||||
{
|
||||
openMenu = UIMenu(title: NSLocalizedString("Open in ...", comment: ""),
|
||||
children: [openApple, openYandex])
|
||||
} else {
|
||||
openApple.title = NSLocalizedString("Open in Apple Maps", comment: "")
|
||||
openMenu = openApple
|
||||
let copy = UIAction(title: NSLocalizedString("Copy", comment: ""), image: UIImage(systemName: "doc.on.doc")) { action in
|
||||
self.copyEvent(index: indexPath.row)
|
||||
}
|
||||
|
||||
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? {
|
||||
guard let vehicle = self.vehicle else {
|
||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||
return nil
|
||||
}
|
||||
|
||||
let event = vehicle.events[indexPath.row]
|
||||
|
||||
let copy = UIContextualAction(style: .normal, title: NSLocalizedString("Copy", comment: "")) { action, view, completion in
|
||||
self.copyEvent(event: event)
|
||||
self.copyEvent(index: indexPath.row)
|
||||
completion(true)
|
||||
}
|
||||
copy.image = UIImage(systemName: "doc.on.doc")
|
||||
copy.backgroundColor = .systemBlue
|
||||
|
||||
let delete = UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { action, view, completion in
|
||||
self.deleteEvent(event: event, completion: completion)
|
||||
self.deleteEvent(index: indexPath.row, completion: completion)
|
||||
}
|
||||
delete.image = UIImage(systemName: "trash")
|
||||
|
||||
let edit = UIContextualAction(style: .normal, title: NSLocalizedString("Edit", comment: "")) { action, view, completion in
|
||||
self.editEvent(event: event)
|
||||
self.editEvent(index: indexPath.row)
|
||||
completion(true)
|
||||
}
|
||||
edit.image = UIImage(systemName: "pencil")
|
||||
@ -241,19 +206,31 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
|
||||
// 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)
|
||||
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)
|
||||
completion?(result)
|
||||
}, onFailure: { error in
|
||||
}, onError: { error in
|
||||
completion?(false)
|
||||
HUD.show(error: error)
|
||||
print(error)
|
||||
}).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 controller = sb.instantiateViewController(identifier: "LocationEditController") as LocationEditController
|
||||
controller.title = NSLocalizedString("Edit event", comment: "")
|
||||
@ -264,8 +241,8 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
self.navigationController?.popViewController(animated: true, completion: {
|
||||
HUD.show(.progress)
|
||||
Api.edit(event: newEvent)
|
||||
.observe(on: MainScheduler.instance)
|
||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onFailure:
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
|
||||
{ error in
|
||||
HUD.show(error: error)
|
||||
})
|
||||
@ -275,8 +252,14 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
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] = [:]
|
||||
let event = vehicle.events[index]
|
||||
|
||||
if let url = event.getMapLink() {
|
||||
items[kUTTypeURL as String] = url
|
||||
@ -295,29 +278,17 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
self.setupBarButtonItems()
|
||||
}
|
||||
|
||||
func shareEvent(event: VehicleEvent) {
|
||||
guard let url = event.getMapLink() else {
|
||||
func shareEvent(index: Int) {
|
||||
guard let vehicle = self.vehicle else {
|
||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||
return
|
||||
}
|
||||
|
||||
let event = vehicle.events[index]
|
||||
if let url = event.getMapLink() {
|
||||
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
||||
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) {
|
||||
@ -333,8 +304,8 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
self.navigationController?.popViewController(animated: true, completion: {
|
||||
HUD.show(.progress)
|
||||
Api.add(event: newEvent, to: vehicle.getNumber())
|
||||
.observe(on: MainScheduler.instance)
|
||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onFailure:
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
|
||||
{ error in
|
||||
HUD.show(error: error)
|
||||
})
|
||||
@ -363,8 +334,8 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
HUD.show(.progress)
|
||||
event.id = UUID().uuidString
|
||||
Api.add(event: event, to: vehicle.getNumber())
|
||||
.observe(on: MainScheduler.instance)
|
||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onFailure:
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
|
||||
{ error in
|
||||
HUD.show(error: error)
|
||||
})
|
||||
|
||||
@ -25,7 +25,7 @@ class GlobalEventsController: UIViewController {
|
||||
|
||||
HUD.show(.progress)
|
||||
Api.events(with: self.filter)
|
||||
.observe(on: MainScheduler.init())
|
||||
.observeOn(MainScheduler.init())
|
||||
.subscribe(onSuccess: { events in
|
||||
self.title = String.localizedStringWithFormat(NSLocalizedString("events found", comment: ""), events.count)
|
||||
let pins = events.map(EventPin.init(event:))
|
||||
@ -33,9 +33,9 @@ class GlobalEventsController: UIViewController {
|
||||
self.map.addAnnotations(pins)
|
||||
self.map.centerOnPins()
|
||||
HUD.hide()
|
||||
}, onFailure: { error in
|
||||
}) { error in
|
||||
HUD.show(error: error)
|
||||
})
|
||||
}
|
||||
.disposed(by: self.bag)
|
||||
}
|
||||
|
||||
|
||||
@ -1,24 +1,9 @@
|
||||
import UIKit
|
||||
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 {
|
||||
|
||||
// MARK: - Views
|
||||
public var onCheck: ((String) -> Void)?
|
||||
|
||||
private lazy var keyboardView: PNKeyboard = {
|
||||
let keyboard = PNKeyboard(target: self.plateView)
|
||||
@ -36,26 +21,21 @@ class NewNumberController: UIViewController {
|
||||
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 = {
|
||||
let button = ACButton(title: NSLocalizedString("Check", comment: ""), onTap: check)
|
||||
button.isEnabled = false
|
||||
button.contentEdgeInsets = .init(top: 0, left: 8, bottom: 0, right: 8)
|
||||
button.accessibilityIdentifier = "checkButton"
|
||||
button.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var stackView: UIStackView = .horizontal([
|
||||
plateView, vinField, checkButton
|
||||
])
|
||||
private lazy var stackView: UIStackView = {
|
||||
let stack = UIStackView(arrangedSubviews: [plateView, checkButton])
|
||||
stack.axis = .horizontal
|
||||
stack.spacing = 16
|
||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||
return stack
|
||||
}()
|
||||
|
||||
private let titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
@ -66,35 +46,13 @@ class NewNumberController: UIViewController {
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var mainStackView: UIStackView = .vertical([
|
||||
titleLabel,
|
||||
stackView,
|
||||
//settingsStackView,
|
||||
keyboardView
|
||||
])
|
||||
|
||||
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
|
||||
private lazy var mainStackView: UIStackView = {
|
||||
let stack = UIStackView(arrangedSubviews: [titleLabel, stackView, keyboardView])
|
||||
stack.axis = .vertical
|
||||
stack.spacing = 16
|
||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||
return stack
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
@ -121,27 +79,6 @@ class NewNumberController: UIViewController {
|
||||
func onNumberChanged() {
|
||||
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 {
|
||||
|
||||
@ -138,11 +138,11 @@ class NotesController: UIViewController, UITableViewDataSource, UITableViewDeleg
|
||||
|
||||
HUD.show(.progress)
|
||||
Api.add(notes: [note], to: vehicle.getNumber())
|
||||
.observe(on: MainScheduler.instance)
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onSuccess: {
|
||||
HUD.hide()
|
||||
self.update(vehicle: $0)
|
||||
}, onFailure: { error in
|
||||
}, onError: { error in
|
||||
HUD.hide()
|
||||
self.show(error: error)
|
||||
})
|
||||
@ -183,11 +183,11 @@ class NotesController: UIViewController, UITableViewDataSource, UITableViewDeleg
|
||||
let newNote = note.clone()
|
||||
newNote.text = noteText
|
||||
Api.edit(note: newNote)
|
||||
.observe(on: MainScheduler.instance)
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onSuccess: {
|
||||
HUD.hide()
|
||||
self.update(vehicle: $0)
|
||||
}, onFailure: { error in
|
||||
}, onError: { error in
|
||||
HUD.hide()
|
||||
self.show(error: error)
|
||||
})
|
||||
@ -217,12 +217,12 @@ class NotesController: UIViewController, UITableViewDataSource, UITableViewDeleg
|
||||
|
||||
HUD.show(.progress)
|
||||
Api.remove(note: note.id)
|
||||
.observe(on: MainScheduler.instance)
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onSuccess: { vehicle in
|
||||
HUD.hide()
|
||||
let result = self.update(vehicle: vehicle)
|
||||
completion?(result)
|
||||
}, onFailure: { error in
|
||||
}, onError: { error in
|
||||
completion?(false)
|
||||
HUD.hide()
|
||||
self.show(error: error)
|
||||
|
||||
@ -71,11 +71,11 @@ class OsagoAddController: FormViewController {
|
||||
}
|
||||
HUD.show(.progress)
|
||||
Api.checkOsago(number: number, vin: vin, date: date, token: token)
|
||||
.observe(on: MainScheduler.instance)
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe { vehicle in
|
||||
HUD.hide()
|
||||
self.onDone?(vehicle)
|
||||
} onFailure: { err in
|
||||
} onError: { err in
|
||||
HUD.show(error: err)
|
||||
}
|
||||
.disposed(by: self.bag)
|
||||
|
||||
@ -2,6 +2,7 @@ import UIKit
|
||||
import AVFoundation
|
||||
import RealmSwift
|
||||
import RxSwift
|
||||
import RxRealm
|
||||
import Intents
|
||||
import CoreSpotlight
|
||||
import MobileCoreServices
|
||||
@ -96,10 +97,10 @@ class RecordsController: UIViewController, UITableViewDelegate {
|
||||
|
||||
let locationObservable = RxLocationManager.requestCurrentLocation()
|
||||
.map(Optional.init)
|
||||
.catchAndReturn(nil)
|
||||
.catchErrorJustReturn(nil)
|
||||
|
||||
let recordObservable: Single<String> = recorder.requestPermissions()
|
||||
.observe(on: MainScheduler.instance)
|
||||
.observeOn(MainScheduler.instance)
|
||||
.flatMap(self.makeStartSoundIfNeeded)
|
||||
.flatMap {
|
||||
#if targetEnvironment(macCatalyst) || targetEnvironment(simulator)
|
||||
@ -140,7 +141,7 @@ class RecordsController: UIViewController, UITableViewDelegate {
|
||||
}
|
||||
alert?.dismiss(animated: true)
|
||||
self.addButton.isEnabled = true
|
||||
}, onFailure: { error in
|
||||
}) { error in
|
||||
if let alert = alert {
|
||||
alert.dismiss(animated: true) {
|
||||
HUD.show(error: error)
|
||||
@ -149,7 +150,7 @@ class RecordsController: UIViewController, UITableViewDelegate {
|
||||
HUD.show(error: error)
|
||||
}
|
||||
self.addButton.isEnabled = true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func showRecordingAlert() -> UIAlertController {
|
||||
|
||||
@ -4,8 +4,6 @@ import LinkPresentation
|
||||
import RealmSwift
|
||||
import Eureka
|
||||
import AutoCatCore
|
||||
import SwiftEntryKit
|
||||
import MobileCoreServices
|
||||
|
||||
class ReportController: FormViewController, MediaBrowserViewControllerDataSource, MediaBrowserViewControllerDelegate, UIActivityItemSource {
|
||||
|
||||
@ -15,10 +13,6 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
|
||||
private var reportImageUrl: URL?
|
||||
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? {
|
||||
didSet {
|
||||
if isViewLoaded && self.view.window != nil {
|
||||
@ -160,43 +154,17 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
|
||||
func setupCopyBehaviour() {
|
||||
|
||||
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
|
||||
guard let text = labelRow.value else {
|
||||
return
|
||||
}
|
||||
|
||||
UIPasteboard.general.string = text
|
||||
let generator = UIImpactFeedbackGenerator(style: .rigid)
|
||||
generator.impactOccurred()
|
||||
let toastMessage = NSLocalizedString("Copied: ", comment: "") + text
|
||||
self.showToast(text: toastMessage)
|
||||
UIPasteboard.general.string = labelRow.value
|
||||
}
|
||||
|
||||
doubleTap.numberOfTapsRequired = 2
|
||||
doubleTap.delaysTouchesBegan = true
|
||||
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) {
|
||||
if let row = self.form.rowBy(tag: tag) as? LabelRow {
|
||||
row.value = value
|
||||
@ -216,8 +184,8 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
|
||||
self.update(row: "Year", with: String(self.vehicle?.year ?? 0))
|
||||
self.update(row: "Color", with: self.vehicle?.color ?? "<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: "Japanese", with: self.stringFromBool(self.vehicle?.isJapanese, yes: NSLocalizedString("Yes", comment: ""), no: NSLocalizedString("No", 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.value, yes: NSLocalizedString("Yes", comment: ""), no: NSLocalizedString("No", comment: "")))
|
||||
|
||||
var num = self.vehicle?.getNumber() ?? "<unknown>"
|
||||
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: "EngineNumber", with: self.vehicle?.engine?.number ?? "<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: "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: "OSAGO", with: String(self.vehicle?.osagoContracts.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
|
||||
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)
|
||||
{
|
||||
if let jwt = try? JWT<EmptyPayload>.generate(for: vehicle.getNumber()), let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt) {
|
||||
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
||||
controller.popoverPresentationController?.barButtonItem = sender
|
||||
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(shareTextAndImage)
|
||||
sheet.addAction(shareLink)
|
||||
sheet.addAction(copyLink)
|
||||
sheet.addAction(cancel)
|
||||
self.present(sheet, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import PKHUD
|
||||
import ExceptionCatcher
|
||||
import AutoCatCore
|
||||
|
||||
class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDelegate, UIScrollViewDelegate, UISearchBarDelegate {
|
||||
class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDelegate, UIScrollViewDelegate {
|
||||
|
||||
@IBOutlet weak var tableView: UITableView!
|
||||
@IBOutlet weak var showMapButton: UIBarButtonItem?
|
||||
@ -20,9 +20,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
||||
private lazy var searchController: UISearchController = .default
|
||||
.placeholder(NSLocalizedString("Search plate numbers", comment: ""))
|
||||
.resultsUpdater(self)
|
||||
.searchBarDelegate(self)
|
||||
.makeDumb()
|
||||
.scopeButtons(SearchScope.allCases.map(\.title))
|
||||
|
||||
private var refreshControl = UIRefreshControl()
|
||||
private var datasource: RxSectionedDataSource<Vehicle,VehicleCell>!
|
||||
@ -74,9 +72,9 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
||||
}
|
||||
return Api.getVehicles(with: filter, pageToken: self.datasource.pageToken)
|
||||
.do(onError: { print($0) })
|
||||
.catchAndReturn(PagedResponse<Vehicle>())
|
||||
.catchErrorJustReturn(PagedResponse<Vehicle>())
|
||||
}
|
||||
.observe(on: MainScheduler.instance)
|
||||
.observeOn(MainScheduler.instance)
|
||||
.do(onNext: {
|
||||
if let count = $0.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.needReset = true
|
||||
self.filter.scope = SearchScope(rawValue: searchController.searchBar.selectedScopeButtonIndex) ?? .plateNumber
|
||||
|
||||
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
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
@ -196,7 +183,6 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
||||
self.filter = controller.filter
|
||||
self.datasource.setSortParameter(self.filter.sortBy ?? .updatedDate)
|
||||
self.filter.needReset = true
|
||||
self.filter.scope = SearchScope(rawValue: self.searchController.searchBar.selectedScopeButtonIndex) ?? .plateNumber
|
||||
self.filterRelay.accept(self.filter)
|
||||
}
|
||||
self.navigationController?.pushViewController(controller, animated: true)
|
||||
@ -217,7 +203,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
||||
showProgress()
|
||||
|
||||
Api.getVehicles(with: filter, pageSize: 0)
|
||||
.observe(on: MainScheduler.instance)
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onSuccess: { resp in
|
||||
self.hideProgress()
|
||||
|
||||
@ -240,7 +226,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
||||
} catch {
|
||||
HUD.show(error: error)
|
||||
}
|
||||
}, onFailure: { error in
|
||||
}, onError: { error in
|
||||
self.hideProgress()
|
||||
HUD.show(error: error)
|
||||
})
|
||||
@ -292,7 +278,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
||||
|
||||
func update(vehicle: Vehicle, at indexPath: IndexPath) {
|
||||
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()
|
||||
do {
|
||||
let realm = try Realm()
|
||||
@ -309,7 +295,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
|
||||
let frozenVehicle = newVehicle.realm != nil ? newVehicle.clone() : newVehicle
|
||||
self.datasource.set(item: frozenVehicle, at: indexPath)
|
||||
self.updateDetailController(with: frozenVehicle)
|
||||
} onFailure: { err in
|
||||
} onError: { err in
|
||||
HUD.show(error: err)
|
||||
}.disposed(by: self.bag)
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ extension AVAudioSession {
|
||||
do {
|
||||
try self.setCategory(category, mode: .default, options: [])
|
||||
} catch {
|
||||
observer(.failure(error))
|
||||
observer(.error(error))
|
||||
}
|
||||
|
||||
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)
|
||||
y += cellHeight
|
||||
var position = "Unknown"
|
||||
if let rightWheel = self.isRightWheel {
|
||||
if let rightWheel = self.isRightWheel.value {
|
||||
position = rightWheel ? "Right" : "Left"
|
||||
}
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Steering wheel position", value: position, context: ctx)
|
||||
y += cellHeight
|
||||
var japanese = "<Unknown>"
|
||||
if let isJapanese = self.isJapanese {
|
||||
if let isJapanese = self.isJapanese.value {
|
||||
japanese = isJapanese ? "Yes" : "No"
|
||||
}
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Japanese", value: japanese, lineMargin: 0, context: ctx)
|
||||
@ -115,11 +115,11 @@ extension Vehicle {
|
||||
y += cellHeight
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Fuel type", value: self.engine?.fuelType ?? "<unknown>", context: ctx)
|
||||
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
|
||||
self.drawCell(y: y, width: w, height: cellHeight, title: "Power (HP)", value: String(self.engine?.powerHp ?? 0), context: ctx)
|
||||
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
|
||||
|
||||
"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 category = self.category { text += "Category: \(category)\n" }
|
||||
var position = "Unknown"
|
||||
if let rightWheel = self.isRightWheel {
|
||||
if let rightWheel = self.isRightWheel.value {
|
||||
position = rightWheel ? "Right" : "Left"
|
||||
}
|
||||
var japanese = "<Unknown>"
|
||||
if let isJapanese = self.isJapanese {
|
||||
if let isJapanese = self.isJapanese.value {
|
||||
japanese = isJapanese ? "Yes" : "No"
|
||||
}
|
||||
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">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>yandexmaps</string>
|
||||
</array>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
|
||||
@ -163,7 +163,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
guard let rootController = self.window?.rootViewController else { return }
|
||||
|
||||
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 controller = sb.instantiateViewController(identifier: "ReportController") as ReportController
|
||||
controller.vehicle = vehicle
|
||||
@ -172,7 +172,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
controller.navigationItem.leftBarButtonItem = BlockBarButtonItem(barButtonSystemItem: .close) { _ in nav.dismiss(animated: true) }
|
||||
rootController.present(nav, animated: true)
|
||||
HUD.hide()
|
||||
} onFailure: { error in
|
||||
} onError: { error in
|
||||
HUD.show(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ import UIKit
|
||||
|
||||
// MARK: - MediaBrowserViewControllerDataSource protocol
|
||||
/// Protocol to supply media browser contents.
|
||||
public protocol MediaBrowserViewControllerDataSource: AnyObject {
|
||||
public protocol MediaBrowserViewControllerDataSource: class {
|
||||
|
||||
/**
|
||||
Completion block for passing requested media image with details.
|
||||
@ -88,7 +88,7 @@ extension MediaBrowserViewControllerDataSource {
|
||||
|
||||
// MARK: - MediaBrowserViewControllerDelegate protocol
|
||||
|
||||
public protocol MediaBrowserViewControllerDelegate: AnyObject {
|
||||
public protocol MediaBrowserViewControllerDelegate: class {
|
||||
|
||||
/**
|
||||
Method invoked on scrolling to next/previous media items.
|
||||
|
||||
@ -45,25 +45,25 @@ class Recorder {
|
||||
break
|
||||
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")
|
||||
observer(.failure(error))
|
||||
observer(.error(error))
|
||||
break
|
||||
case .restricted:
|
||||
let error = CocoaError.error("Access error", reason: "Speech recognition is restricted on this device")
|
||||
observer(.failure(error))
|
||||
observer(.error(error))
|
||||
break
|
||||
case .notDetermined:
|
||||
let error = CocoaError.error("Access error", reason: "Speech recognition status is not yet determined")
|
||||
observer(.failure(error))
|
||||
observer(.error(error))
|
||||
break
|
||||
@unknown default:
|
||||
let error = CocoaError.error("Access error", reason: "Unknown error accessing speech recognizer")
|
||||
observer(.failure(error))
|
||||
observer(.error(error))
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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
|
||||
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()
|
||||
}
|
||||
|
||||
ExtAudioFileCreateWithURL(file as CFURL, kAudioFileM4AType, aac.streamDescription, nil, AudioFileFlags.eraseFile.rawValue, &self.fileRef)
|
||||
guard let fileRef = self.fileRef else {
|
||||
observer(.failure(CocoaError.error(CocoaError.Code.fileWriteUnknown)))
|
||||
observer(.error(CocoaError.error(CocoaError.Code.fileWriteUnknown)))
|
||||
return Disposables.create()
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ class Recorder {
|
||||
self.engine.prepare()
|
||||
try self.engine.start()
|
||||
} catch {
|
||||
observer(.failure(error))
|
||||
observer(.error(error))
|
||||
}
|
||||
|
||||
return Disposables.create {
|
||||
|
||||
@ -15,57 +15,28 @@ enum PNButtonType {
|
||||
case done
|
||||
}
|
||||
|
||||
enum PNKeyboardType {
|
||||
|
||||
case plateNumber
|
||||
case vin
|
||||
}
|
||||
|
||||
class PNButton: UIButton {
|
||||
private(set) var type: PNButtonType
|
||||
private var keyboardType: PNKeyboardType = .plateNumber
|
||||
private var rectLayer = CAShapeLayer()
|
||||
private var bgColor = UIColor(named: "KeyBackground")
|
||||
|
||||
weak var delegate: PNButtonDelegate?
|
||||
|
||||
var letterFont: UIFont? {
|
||||
|
||||
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) {
|
||||
init(letter: Character) {
|
||||
self.type = .symbol(String(letter))
|
||||
self.keyboardType = keyboardType
|
||||
super.init(frame: .zero)
|
||||
self.setup()
|
||||
self.titleLabel?.font = letterFont
|
||||
self.titleLabel?.font = UIFont(name: "RoadNumbers", size: 36)
|
||||
let title = String(Constants.pnLettersMap[letter] ?? letter)
|
||||
self.setTitle(title, for: .normal)
|
||||
self.setTitleColor(.label, for: .normal)
|
||||
}
|
||||
|
||||
init(digit: Int, keyboardType: PNKeyboardType = .plateNumber) {
|
||||
init(digit: Int) {
|
||||
self.type = .symbol(String(digit))
|
||||
self.keyboardType = keyboardType
|
||||
super.init(frame: .zero)
|
||||
self.setup()
|
||||
self.titleLabel?.font = digitFont
|
||||
self.titleLabel?.font = UIFont(name: "RoadNumbersCyr-Regular", size: 30)
|
||||
let character = Character(String(digit))
|
||||
let title = String(Constants.pnLettersMap[character] ?? character)
|
||||
self.setTitle(title, for: .normal)
|
||||
@ -127,52 +98,20 @@ class PNButton: UIButton {
|
||||
}
|
||||
|
||||
class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
||||
public weak var target: UIKeyInput?
|
||||
private weak var target: UIKeyInput?
|
||||
weak var delegate: PNKeyboardDelegate?
|
||||
|
||||
private let insets: UIEdgeInsets
|
||||
|
||||
public var type: PNKeyboardType {
|
||||
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) {
|
||||
init(target: UIKeyInput, insets: UIEdgeInsets = .zero) {
|
||||
self.target = target
|
||||
self.insets = insets
|
||||
self.type = type
|
||||
super.init(frame: .zero)
|
||||
self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
|
||||
let blurEffectView = UIVisualEffectView(effect: UIBlurEffect())
|
||||
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||
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()
|
||||
}
|
||||
@ -181,53 +120,14 @@ class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
||||
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() {
|
||||
let letterButtons: [PNButton] = letters.sorted().map { letter in
|
||||
let button = PNButton(letter: letter, keyboardType: type)
|
||||
let letters: [PNButton] = Constants.pnLettersMap.keys.sorted().map { letter in
|
||||
let button = PNButton(letter: letter)
|
||||
button.delegate = self
|
||||
return button
|
||||
}
|
||||
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
|
||||
return button
|
||||
}
|
||||
@ -239,8 +139,14 @@ class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
||||
done.setBacgroundColor(color: .systemBlue)
|
||||
done.tintColor = .white
|
||||
|
||||
let rows = letterRows(from: letterButtons)
|
||||
let lettersStack = UIStackView(arrangedSubviews: rows)
|
||||
let letterRows = [
|
||||
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.distribution = .fillEqually
|
||||
//lettersStack.spacing = 8
|
||||
@ -257,15 +163,18 @@ class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
||||
digitsStack.distribution = .fillEqually
|
||||
//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)
|
||||
digitsWidthConstraint = digitsStack.widthAnchor.constraint(equalToConstant: 0)
|
||||
|
||||
lettersWidthConstraint?.priority = .defaultLow
|
||||
digitsWidthConstraint?.priority = .defaultLow
|
||||
|
||||
NSLayoutConstraint.activate([lettersWidthConstraint, digitsWidthConstraint].compactMap { $0 })
|
||||
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)
|
||||
])
|
||||
}
|
||||
|
||||
func createLetterStack(_ views: [UIView]) -> UIStackView {
|
||||
|
||||
@ -403,5 +403,3 @@
|
||||
/* No comment provided by engineer. */
|
||||
"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 {
|
||||
|
||||
@Persisted public var path: String = ""
|
||||
@Persisted public var number: String?
|
||||
@Persisted public var rawText: String = ""
|
||||
@Persisted private var addedDate: TimeInterval = 0
|
||||
@Persisted public var duration: TimeInterval = 0
|
||||
@Persisted public var event: VehicleEvent?
|
||||
@objc public dynamic var path: String = ""
|
||||
@objc public dynamic var number: String?
|
||||
@objc public dynamic var rawText: String = ""
|
||||
@objc private dynamic var addedDate: TimeInterval = 0
|
||||
@objc public dynamic var duration: TimeInterval = 0
|
||||
@objc public dynamic var event: VehicleEvent?
|
||||
|
||||
public var identifier: TimeInterval = 0
|
||||
public var id: TimeInterval {
|
||||
@ -33,7 +33,7 @@ public class AudioRecord: Object, Identifiable, Cloneable {
|
||||
self.addedDate = Date().timeIntervalSince1970
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
|
||||
@ -8,17 +8,17 @@ public enum DebugInfoStatus: Int {
|
||||
}
|
||||
|
||||
public class DebugInfo: Object, Decodable {
|
||||
@Persisted public var autocod: DebugInfoEntry!
|
||||
@Persisted public var vin01vin: DebugInfoEntry!
|
||||
@Persisted public var vin01base: DebugInfoEntry!
|
||||
@Persisted public var vin01history: DebugInfoEntry!
|
||||
@Persisted public var nomerogram: DebugInfoEntry!
|
||||
@objc public dynamic var autocod: DebugInfoEntry!
|
||||
@objc public dynamic var vin01vin: DebugInfoEntry!
|
||||
@objc public dynamic var vin01base: DebugInfoEntry!
|
||||
@objc public dynamic var vin01history: DebugInfoEntry!
|
||||
@objc public dynamic var nomerogram: DebugInfoEntry!
|
||||
}
|
||||
|
||||
public class DebugInfoEntry: Object, Decodable {
|
||||
@Persisted public var fields: Int64 = 0
|
||||
@Persisted public var error: String?
|
||||
@Persisted public var status: Int = 0
|
||||
@objc public dynamic var fields: Int64 = 0
|
||||
@objc public dynamic var error: String?
|
||||
@objc public dynamic var status: Int = 0
|
||||
|
||||
public var statusEnum: DebugInfoStatus {
|
||||
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 var searchString = ""
|
||||
public var brand: String?
|
||||
@ -78,7 +55,6 @@ public struct Filter {
|
||||
public var fromLocationDate: Date?
|
||||
public var toLocationDate: Date?
|
||||
public var needReset: Bool = false
|
||||
public var scope: SearchScope = .plateNumber
|
||||
|
||||
public init() {
|
||||
}
|
||||
@ -98,7 +74,6 @@ public struct Filter {
|
||||
self.toDateUpdated = nil
|
||||
self.fromLocationDate = nil
|
||||
self.toLocationDate = nil
|
||||
self.scope = .plateNumber
|
||||
}
|
||||
|
||||
public func queryDictionary() -> [String: String] {
|
||||
@ -147,8 +122,6 @@ public struct Filter {
|
||||
dict["toLocationDate"] = String(toLocationDate.timeIntervalSince1970)
|
||||
}
|
||||
|
||||
dict["scope"] = scope.stringValue
|
||||
|
||||
return dict
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,16 +2,16 @@ import Foundation
|
||||
import RealmSwift
|
||||
|
||||
public class Osago: Object, Decodable, Cloneable {
|
||||
@Persisted public var date: TimeInterval = 0
|
||||
@Persisted public var number: String = ""
|
||||
@Persisted public var vin: String?
|
||||
@Persisted public var plateNumber: String?
|
||||
@Persisted public var name: String = ""
|
||||
@Persisted public var status: String = ""
|
||||
@Persisted public var restrictions: String = ""
|
||||
@Persisted public var insurant: String?
|
||||
@Persisted public var owner: String?
|
||||
@Persisted public var usageRegion: String?
|
||||
@objc public dynamic var date: TimeInterval = 0
|
||||
@objc public dynamic var number: String = ""
|
||||
@objc public dynamic var vin: String?
|
||||
@objc public dynamic var plateNumber: String?
|
||||
@objc public dynamic var name: String = ""
|
||||
@objc public dynamic var status: String = ""
|
||||
@objc public dynamic var restrictions: String = ""
|
||||
@objc public dynamic var insurant: String?
|
||||
@objc public dynamic var owner: String?
|
||||
@objc public dynamic var usageRegion: String?
|
||||
|
||||
public required init(copy: Osago) {
|
||||
self.date = copy.date
|
||||
@ -26,7 +26,7 @@ public class Osago: Object, Decodable, Cloneable {
|
||||
self.usageRegion = copy.usageRegion
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,50 +2,50 @@ import Foundation
|
||||
import RealmSwift
|
||||
|
||||
public class VehicleName: Object, Decodable, Cloneable {
|
||||
@Persisted public var original: String?
|
||||
@Persisted public var normalized: String?
|
||||
@objc public dynamic var original: String?
|
||||
@objc public dynamic var normalized: String?
|
||||
|
||||
public required init(copy: VehicleName) {
|
||||
self.original = copy.original
|
||||
self.normalized = copy.normalized
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
}
|
||||
}
|
||||
|
||||
public class VehicleBrand: Object, Decodable, Cloneable {
|
||||
@Persisted public var name: VehicleName?
|
||||
@Persisted public var logo: String?
|
||||
@objc public dynamic var name: VehicleName?
|
||||
@objc public dynamic var logo: String?
|
||||
|
||||
public required init(copy: VehicleBrand) {
|
||||
self.name = copy.name?.clone()
|
||||
self.logo = copy.logo
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
public class VehicleModel: Object, Decodable, Cloneable {
|
||||
@Persisted var name: VehicleName?
|
||||
@objc dynamic var name: VehicleName?
|
||||
|
||||
public required init(copy: VehicleModel) {
|
||||
self.name = copy.name?.clone()
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
public class VehicleEngine: Object, Decodable, Cloneable {
|
||||
@Persisted public var number: String?
|
||||
@Persisted public var volume: Int? = 0
|
||||
@Persisted public var powerHp: Float? = 0
|
||||
@Persisted public var powerKw: Float? = 0
|
||||
@Persisted public var fuelType: String?
|
||||
@objc public dynamic var number: String?
|
||||
public var volume: RealmOptional<Int> = RealmOptional(0)
|
||||
@objc public dynamic var powerHp: Float = 0
|
||||
public var powerKw: RealmOptional<Float> = RealmOptional(0)
|
||||
@objc public dynamic var fuelType: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case number, volume, powerHp, powerKw, fuelType
|
||||
@ -54,13 +54,13 @@ public class VehicleEngine: Object, Decodable, Cloneable {
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.number = try container.decodeIfPresent(String.self, forKey: .number)
|
||||
self.volume = try container.decodeIfPresent(Int.self, forKey: .volume)
|
||||
self.powerHp = try container.decodeIfPresent(Float.self, forKey: .powerHp)
|
||||
self.powerKw = try container.decodeIfPresent(Float.self, forKey: .powerKw)
|
||||
self.volume = RealmOptional(try container.decodeIfPresent(Int.self, forKey: .volume))
|
||||
self.powerHp = try container.decode(Float.self, forKey: .powerHp)
|
||||
self.powerKw = RealmOptional(try container.decodeIfPresent(Float.self, forKey: .powerKw))
|
||||
self.fuelType = try container.decodeIfPresent(String.self, forKey: .fuelType)
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
@ -74,10 +74,10 @@ public class VehicleEngine: Object, Decodable, Cloneable {
|
||||
}
|
||||
|
||||
public class VehiclePhoto: Object, Decodable, Cloneable {
|
||||
@Persisted public var brand: String?
|
||||
@Persisted public var model: String?
|
||||
@Persisted public var date: TimeInterval = 0
|
||||
@Persisted public var url: String = ""
|
||||
@objc public dynamic var brand: String?
|
||||
@objc public dynamic var model: String?
|
||||
@objc public dynamic var date: TimeInterval = 0
|
||||
@objc public dynamic var url: String = ""
|
||||
|
||||
public override var description: String {
|
||||
let formatter = DateFormatter()
|
||||
@ -96,7 +96,7 @@ public class VehiclePhoto: Object, Decodable, Cloneable {
|
||||
self.url = copy.url
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
@ -128,17 +128,17 @@ public enum SteeringWheelPosition: CustomStringConvertible {
|
||||
}
|
||||
|
||||
public class VehicleOwnershipPeriod: Object, Decodable, Cloneable {
|
||||
@Persisted public var lastOperation: String = ""
|
||||
@Persisted public var ownerType: String = ""
|
||||
@Persisted public var from: Int64 = 0
|
||||
@Persisted public var to: Int64 = 0
|
||||
@Persisted public var region: String?
|
||||
@Persisted public var registrationRegion: String?
|
||||
@Persisted public var locality: String?
|
||||
@Persisted public var code: String?
|
||||
@Persisted public var street: String?
|
||||
@Persisted public var building: String?
|
||||
@Persisted public var inn: String?
|
||||
@objc public dynamic var lastOperation: String = ""
|
||||
@objc public dynamic var ownerType: String = ""
|
||||
@objc public dynamic var from: Int64 = 0
|
||||
@objc public dynamic var to: Int64 = 0
|
||||
@objc public dynamic var region: String?
|
||||
@objc public dynamic var registrationRegion: String?
|
||||
@objc public dynamic var locality: String?
|
||||
@objc public dynamic var code: String?
|
||||
@objc public dynamic var street: String?
|
||||
@objc public dynamic var building: String?
|
||||
@objc public dynamic var inn: String?
|
||||
|
||||
required public init(copy: VehicleOwnershipPeriod) {
|
||||
self.lastOperation = copy.lastOperation
|
||||
@ -154,37 +154,37 @@ public class VehicleOwnershipPeriod: Object, Decodable, Cloneable {
|
||||
self.inn = copy.inn
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportable {
|
||||
@Persisted public var brand: VehicleBrand?
|
||||
@Persisted public var model: VehicleModel?
|
||||
@Persisted public var color: String?
|
||||
@Persisted public var year: Int = 0
|
||||
@Persisted public var category: String?
|
||||
@Persisted public var engine: VehicleEngine?
|
||||
@Persisted private var number: String = ""
|
||||
@Persisted public var currentNumber: String?
|
||||
@Persisted public var vin1: String?
|
||||
@Persisted public var vin2: String?
|
||||
@Persisted public var sts: String?
|
||||
@Persisted public var pts: String?
|
||||
@Persisted public var isRightWheel: Bool?
|
||||
@Persisted public var isJapanese: Bool?
|
||||
@Persisted public var addedDate: TimeInterval = 0
|
||||
@Persisted public var updatedDate: TimeInterval = 0
|
||||
@Persisted public var addedBy: String = ""
|
||||
@Persisted public var photos: List<VehiclePhoto>
|
||||
@Persisted public var ownershipPeriods: List<VehicleOwnershipPeriod>
|
||||
@Persisted public var events: List<VehicleEvent>
|
||||
@Persisted public var osagoContracts: List<Osago>
|
||||
@Persisted public var ads: List<VehicleAd>
|
||||
@Persisted public var notes: List<VehicleNote>
|
||||
@Persisted public var debugInfo: DebugInfo?
|
||||
@Persisted public var synchronized: Bool = true
|
||||
@objc public dynamic var brand: VehicleBrand?
|
||||
@objc public dynamic var model: VehicleModel?
|
||||
@objc public dynamic var color: String?
|
||||
@objc public dynamic var year: Int = 0
|
||||
@objc public dynamic var category: String?
|
||||
@objc public dynamic var engine: VehicleEngine?
|
||||
@objc private dynamic var number: String = ""
|
||||
@objc public dynamic var currentNumber: String?
|
||||
@objc public dynamic var vin1: String?
|
||||
@objc public dynamic var vin2: String?
|
||||
@objc public dynamic var sts: String?
|
||||
@objc public dynamic var pts: String?
|
||||
public var isRightWheel = RealmOptional<Bool>()
|
||||
public var isJapanese: RealmOptional<Bool> = RealmOptional<Bool>()
|
||||
@objc public dynamic var addedDate: TimeInterval = 0
|
||||
@objc public dynamic var updatedDate: TimeInterval = 0
|
||||
@objc public dynamic var addedBy: String = ""
|
||||
public var photos = List<VehiclePhoto>()
|
||||
public var ownershipPeriods = List<VehicleOwnershipPeriod>()
|
||||
public var events = List<VehicleEvent>()
|
||||
public var osagoContracts = List<Osago>()
|
||||
public var ads = List<VehicleAd>()
|
||||
public var notes = List<VehicleNote>()
|
||||
@objc public dynamic var debugInfo: DebugInfo?
|
||||
@objc public dynamic var synchronized: Bool = true
|
||||
|
||||
lazy var formatter: DateFormatter = {
|
||||
let f = DateFormatter()
|
||||
@ -221,8 +221,6 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
super.init()
|
||||
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.brand = try container.decodeIfPresent(VehicleBrand.self, forKey: .brand)
|
||||
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.sts = try container.decodeIfPresent(String.self, forKey: .sts)
|
||||
self.pts = try container.decodeIfPresent(String.self, forKey: .pts)
|
||||
self.isRightWheel = try container.decodeIfPresent(Bool.self, forKey: .isRightWheel)
|
||||
self.isJapanese = try container.decodeIfPresent(Bool.self, forKey: .isJapanese)
|
||||
self.isRightWheel = RealmOptional(try container.decodeIfPresent(Bool.self, forKey: .isRightWheel))
|
||||
self.isJapanese = RealmOptional(try container.decodeIfPresent(Bool.self, forKey: .isJapanese))
|
||||
self.addedDate = (try container.decode(TimeInterval.self, forKey: .addedDate))/1000
|
||||
self.addedBy = try container.decode(String.self, forKey: .addedBy)
|
||||
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
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
public init(_ number: String) {
|
||||
super.init()
|
||||
self.number = number
|
||||
self.addedDate = Date().timeIntervalSince1970
|
||||
self.updatedDate = self.addedDate
|
||||
@ -378,7 +375,7 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
||||
// MARK: - Exportable
|
||||
|
||||
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 {
|
||||
@ -399,7 +396,7 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
||||
|
||||
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,
|
||||
model,
|
||||
self.color ?? "",
|
||||
@ -410,7 +407,6 @@ public final class Vehicle: Object, Decodable, Identifiable, Cloneable, Exportab
|
||||
self.vin1 ?? "",
|
||||
self.sts ?? "",
|
||||
self.pts ?? "",
|
||||
self.engine?.number ?? "",
|
||||
added,
|
||||
updated,
|
||||
eventsString,
|
||||
|
||||
@ -2,15 +2,15 @@ import Foundation
|
||||
import RealmSwift
|
||||
|
||||
public class VehicleAd: Object, Decodable, Cloneable {
|
||||
@Persisted public var id: Int = 0
|
||||
@Persisted public var url: String?
|
||||
@Persisted public var price: String?
|
||||
@Persisted public var date: TimeInterval = Date().timeIntervalSince1970
|
||||
@Persisted public var mileage: String?
|
||||
@Persisted public var region: String?
|
||||
@Persisted public var city: String?
|
||||
@Persisted public var adDescription: String?
|
||||
@Persisted public var photos: List<String>
|
||||
@objc public dynamic var id: Int = 0
|
||||
@objc public dynamic var url: String?
|
||||
@objc public dynamic var price: String?
|
||||
@objc public dynamic var date: TimeInterval = Date().timeIntervalSince1970
|
||||
@objc public dynamic var mileage: String?
|
||||
@objc public dynamic var region: String?
|
||||
@objc public dynamic var city: String?
|
||||
@objc public dynamic var adDescription: String?
|
||||
public var photos = List<String>()
|
||||
|
||||
public required init(copy: VehicleAd) {
|
||||
self.id = copy.id
|
||||
@ -27,7 +27,7 @@ public class VehicleAd: Object, Decodable, Cloneable {
|
||||
self.photos = photos
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,12 +4,12 @@ import RxSwift
|
||||
import CoreLocation
|
||||
|
||||
public class VehicleEvent: Object, Codable, Cloneable {
|
||||
@Persisted public var id: String = UUID().uuidString
|
||||
@Persisted public var date: TimeInterval = Date().timeIntervalSince1970
|
||||
@Persisted public var latitude: Double = 0
|
||||
@Persisted public var longitude: Double = 0
|
||||
@Persisted public var address: String? = nil
|
||||
@Persisted public var addedBy: String? = nil
|
||||
@objc public dynamic var id: String = UUID().uuidString
|
||||
@objc public dynamic var date: TimeInterval = Date().timeIntervalSince1970
|
||||
@objc public dynamic var latitude: Double = 0
|
||||
@objc public dynamic var longitude: Double = 0
|
||||
@objc public dynamic var address: String? = nil
|
||||
@objc public dynamic var addedBy: String? = nil
|
||||
|
||||
public var number: String?
|
||||
public var coordinate: CLLocationCoordinate2D {
|
||||
@ -22,7 +22,7 @@ public class VehicleEvent: Object, Codable, Cloneable {
|
||||
self.addedBy = Settings.shared.user.email
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
@ -78,20 +78,4 @@ public class VehicleEvent: Object, Codable, Cloneable {
|
||||
self.number = copy.number
|
||||
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
|
||||
|
||||
public class VehicleNote: Object, Codable, Cloneable {
|
||||
@Persisted public var id: String = UUID().uuidString
|
||||
@Persisted public var user: String = ""
|
||||
@Persisted public var date: TimeInterval = Date().timeIntervalSince1970
|
||||
@Persisted public var text: String = ""
|
||||
@objc public dynamic var id: String = UUID().uuidString
|
||||
@objc public dynamic var user: String = ""
|
||||
@objc public dynamic var date: TimeInterval = Date().timeIntervalSince1970
|
||||
@objc public dynamic var text: String = ""
|
||||
|
||||
// MARK: - Cloneable
|
||||
|
||||
@ -16,7 +16,7 @@ public class VehicleNote: Object, Codable, Cloneable {
|
||||
self.text = copy.text
|
||||
}
|
||||
|
||||
required override init() {
|
||||
required init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,7 @@ public class Api {
|
||||
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)
|
||||
// print("================================")
|
||||
// if let string = str?.replacingOccurrences(of: "\\\"", with: "\"")
|
||||
@ -55,15 +55,6 @@ public class Api {
|
||||
// print(string)
|
||||
// }
|
||||
// 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 {
|
||||
let resp = try JSONDecoder().decode(Response<T>.self, from: data)
|
||||
if resp.success {
|
||||
@ -172,7 +163,7 @@ public class Api {
|
||||
Settings.shared.user.firebaseRefreshToken = newRefreshToken
|
||||
print("Refresh token: \(newRefreshToken)")
|
||||
}
|
||||
}.catch { err in
|
||||
}.catchError { err in
|
||||
print(err)
|
||||
return .just(())
|
||||
}
|
||||
|
||||
@ -15,10 +15,6 @@ public enum Constants {
|
||||
"А": "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 googleTokenURL = "https://oauth2.googleapis.com/token"
|
||||
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) {
|
||||
observer(.success(()))
|
||||
} 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:
|
||||
observer(.failure(CLError(.denied)))
|
||||
observer(.error(CLError(.denied)))
|
||||
break
|
||||
default:
|
||||
observer(.failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Location permission error"])))
|
||||
observer(.error(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Location permission error"])))
|
||||
break
|
||||
}
|
||||
|
||||
@ -139,11 +139,11 @@ public class RxLocationManager {
|
||||
let location = CLLocation(latitude: latitude, longitude: longitude)
|
||||
geocoder.reverseGeocodeLocation(location) { placemarks, error in
|
||||
if let error = error {
|
||||
observer(.failure(error))
|
||||
observer(.error(error))
|
||||
} else if let placemark = placemarks?.first, let name = placemark.name {
|
||||
observer(.success(name))
|
||||
} 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