New custom keyboard for entering plate numbers
This commit is contained in:
parent
9faa57a4eb
commit
f6d13af17e
@ -49,7 +49,6 @@
|
|||||||
7A488C3D24A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3924A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift */; };
|
7A488C3D24A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3924A74B990054D0B2 /* RxCollectionViewRealmDataSource.swift */; };
|
||||||
7A488C3E24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3A24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift */; };
|
7A488C3E24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3A24A74B990054D0B2 /* Reactive+RxRealmDataSources.swift */; };
|
||||||
7A488C3F24A74B990054D0B2 /* RealmBindObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3B24A74B990054D0B2 /* RealmBindObserver.swift */; };
|
7A488C3F24A74B990054D0B2 /* RealmBindObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A488C3B24A74B990054D0B2 /* RealmBindObserver.swift */; };
|
||||||
7A530B78240010D900CBFE6E /* InputMask in Frameworks */ = {isa = PBXBuildFile; productRef = 7A530B77240010D900CBFE6E /* InputMask */; };
|
|
||||||
7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7924001D3300CBFE6E /* CheckController.swift */; };
|
7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7924001D3300CBFE6E /* CheckController.swift */; };
|
||||||
7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */; };
|
7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */; };
|
||||||
7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7F2401803A00CBFE6E /* Vehicle.swift */; };
|
7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7F2401803A00CBFE6E /* Vehicle.swift */; };
|
||||||
@ -94,6 +93,9 @@
|
|||||||
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; };
|
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; };
|
||||||
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C92250B954900F237B2 /* Navigation.swift */; };
|
7ADF6C93250B954900F237B2 /* Navigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C92250B954900F237B2 /* Navigation.swift */; };
|
||||||
7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C94250D037700F237B2 /* ShowEventController.swift */; };
|
7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C94250D037700F237B2 /* ShowEventController.swift */; };
|
||||||
|
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C96250F41B000F237B2 /* PNKeyboard.swift */; };
|
||||||
|
7ADF6C99250F872C00F237B2 /* RoadNumbers.otf in Resources */ = {isa = PBXBuildFile; fileRef = 7ADF6C98250F872C00F237B2 /* RoadNumbers.otf */; };
|
||||||
|
7ADF6C9D250FA96000F237B2 /* SwiftMaskTextfield.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7ADF6C9C250FA96000F237B2 /* SwiftMaskTextfield.swift */; };
|
||||||
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */; };
|
7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */; };
|
||||||
7AE26A3524F31B0700625033 /* EventsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3424F31B0700625033 /* EventsController.swift */; };
|
7AE26A3524F31B0700625033 /* EventsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AE26A3424F31B0700625033 /* EventsController.swift */; };
|
||||||
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFE727240455E200910EB7 /* SettingsController.swift */; };
|
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFE727240455E200910EB7 /* SettingsController.swift */; };
|
||||||
@ -183,6 +185,9 @@
|
|||||||
7AB67E8D2435D1A000258F61 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; };
|
7AB67E8D2435D1A000258F61 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; };
|
||||||
7ADF6C92250B954900F237B2 /* Navigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Navigation.swift; sourceTree = "<group>"; };
|
7ADF6C92250B954900F237B2 /* Navigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Navigation.swift; sourceTree = "<group>"; };
|
||||||
7ADF6C94250D037700F237B2 /* ShowEventController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowEventController.swift; sourceTree = "<group>"; };
|
7ADF6C94250D037700F237B2 /* ShowEventController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowEventController.swift; sourceTree = "<group>"; };
|
||||||
|
7ADF6C96250F41B000F237B2 /* PNKeyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PNKeyboard.swift; sourceTree = "<group>"; };
|
||||||
|
7ADF6C98250F872C00F237B2 /* RoadNumbers.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = RoadNumbers.otf; sourceTree = "<group>"; };
|
||||||
|
7ADF6C9C250FA96000F237B2 /* SwiftMaskTextfield.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMaskTextfield.swift; sourceTree = "<group>"; };
|
||||||
7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerExt.swift; sourceTree = "<group>"; };
|
7AE26A3224EEF9EC00625033 /* UIViewControllerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIViewControllerExt.swift; sourceTree = "<group>"; };
|
||||||
7AE26A3424F31B0700625033 /* EventsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventsController.swift; sourceTree = "<group>"; };
|
7AE26A3424F31B0700625033 /* EventsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventsController.swift; sourceTree = "<group>"; };
|
||||||
7AEFE727240455E200910EB7 /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
|
7AEFE727240455E200910EB7 /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
|
||||||
@ -209,7 +214,6 @@
|
|||||||
7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */,
|
7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */,
|
||||||
7A11471F23FEA18700B424AF /* RxRelay in Frameworks */,
|
7A11471F23FEA18700B424AF /* RxRelay in Frameworks */,
|
||||||
7AF58D2F24029C5200CE01A0 /* MagazineLayout in Frameworks */,
|
7AF58D2F24029C5200CE01A0 /* MagazineLayout in Frameworks */,
|
||||||
7A530B78240010D900CBFE6E /* InputMask in Frameworks */,
|
|
||||||
7A11471D23FEA18700B424AF /* RxSwift in Frameworks */,
|
7A11471D23FEA18700B424AF /* RxSwift in Frameworks */,
|
||||||
7A11472623FEA1F400B424AF /* Realm in Frameworks */,
|
7A11472623FEA1F400B424AF /* Realm in Frameworks */,
|
||||||
);
|
);
|
||||||
@ -285,6 +289,7 @@
|
|||||||
7A6DD90724329144009DE740 /* CenterTextLayer.swift */,
|
7A6DD90724329144009DE740 /* CenterTextLayer.swift */,
|
||||||
7A96AE32246C095700297C33 /* Base64FS.swift */,
|
7A96AE32246C095700297C33 /* Base64FS.swift */,
|
||||||
7A15051124DB3E3000F39631 /* AnyEncodable.swift */,
|
7A15051124DB3E3000F39631 /* AnyEncodable.swift */,
|
||||||
|
7ADF6C9C250FA96000F237B2 /* SwiftMaskTextfield.swift */,
|
||||||
);
|
);
|
||||||
path = ThirdParty;
|
path = ThirdParty;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -404,6 +409,7 @@
|
|||||||
7AB67E8B2435C38700258F61 /* CustomTextField.swift */,
|
7AB67E8B2435C38700258F61 /* CustomTextField.swift */,
|
||||||
7AB67E8D2435D1A000258F61 /* CustomButton.swift */,
|
7AB67E8D2435D1A000258F61 /* CustomButton.swift */,
|
||||||
7A1090EB24A4E3E100B4F0B2 /* CellProgressView.swift */,
|
7A1090EB24A4E3E100B4F0B2 /* CellProgressView.swift */,
|
||||||
|
7ADF6C96250F41B000F237B2 /* PNKeyboard.swift */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -411,6 +417,7 @@
|
|||||||
7A6DD90424326788009DE740 /* Fonts */ = {
|
7A6DD90424326788009DE740 /* Fonts */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
7ADF6C98250F872C00F237B2 /* RoadNumbers.otf */,
|
||||||
7A6DD90924329541009DE740 /* RoadNumbers2.0.otf */,
|
7A6DD90924329541009DE740 /* RoadNumbers2.0.otf */,
|
||||||
);
|
);
|
||||||
path = Fonts;
|
path = Fonts;
|
||||||
@ -451,7 +458,6 @@
|
|||||||
7A11472223FEA18700B424AF /* RxBlocking */,
|
7A11472223FEA18700B424AF /* RxBlocking */,
|
||||||
7A11472523FEA1F400B424AF /* Realm */,
|
7A11472523FEA1F400B424AF /* Realm */,
|
||||||
7A11472723FEA1F400B424AF /* RealmSwift */,
|
7A11472723FEA1F400B424AF /* RealmSwift */,
|
||||||
7A530B77240010D900CBFE6E /* InputMask */,
|
|
||||||
7A530B8A240181F500CBFE6E /* RxRealm */,
|
7A530B8A240181F500CBFE6E /* RxRealm */,
|
||||||
7AF58D2E24029C5200CE01A0 /* MagazineLayout */,
|
7AF58D2E24029C5200CE01A0 /* MagazineLayout */,
|
||||||
7AF58D332402A91C00CE01A0 /* Kingfisher */,
|
7AF58D332402A91C00CE01A0 /* Kingfisher */,
|
||||||
@ -492,7 +498,6 @@
|
|||||||
packageReferences = (
|
packageReferences = (
|
||||||
7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */,
|
7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */,
|
||||||
7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */,
|
7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */,
|
||||||
7A530B76240010D900CBFE6E /* XCRemoteSwiftPackageReference "input-mask-ios" */,
|
|
||||||
7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */,
|
7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */,
|
||||||
7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */,
|
7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */,
|
||||||
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */,
|
||||||
@ -515,6 +520,7 @@
|
|||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
7ADF6C99250F872C00F237B2 /* RoadNumbers.otf in Resources */,
|
||||||
7A7547DE2403180A004E8406 /* SectionHeader.xib in Resources */,
|
7A7547DE2403180A004E8406 /* SectionHeader.xib in Resources */,
|
||||||
7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */,
|
7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */,
|
||||||
7A6DD90A24329541009DE740 /* RoadNumbers2.0.otf in Resources */,
|
7A6DD90A24329541009DE740 /* RoadNumbers2.0.otf in Resources */,
|
||||||
@ -537,6 +543,7 @@
|
|||||||
7A96AE31246B2FE400297C33 /* Constants.swift in Sources */,
|
7A96AE31246B2FE400297C33 /* Constants.swift in Sources */,
|
||||||
7A64AE822469E16100ABE48E /* IHProgressHUD.swift in Sources */,
|
7A64AE822469E16100ABE48E /* IHProgressHUD.swift in Sources */,
|
||||||
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */,
|
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */,
|
||||||
|
7ADF6C9D250FA96000F237B2 /* SwiftMaskTextfield.swift in Sources */,
|
||||||
7A27ADF924A09CAD0035F39E /* CocoaError.swift in Sources */,
|
7A27ADF924A09CAD0035F39E /* CocoaError.swift in Sources */,
|
||||||
7A813DC9250B5C9700CC93B9 /* LocationRow.swift in Sources */,
|
7A813DC9250B5C9700CC93B9 /* LocationRow.swift in Sources */,
|
||||||
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */,
|
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */,
|
||||||
@ -600,6 +607,7 @@
|
|||||||
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,
|
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,
|
||||||
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
|
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
|
||||||
7A64AE812469E16100ABE48E /* ProgressAnimatedView.swift in Sources */,
|
7A64AE812469E16100ABE48E /* ProgressAnimatedView.swift in Sources */,
|
||||||
|
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
|
||||||
7A000AA224C2EEDE001F5B00 /* Location.swift in Sources */,
|
7A000AA224C2EEDE001F5B00 /* Location.swift in Sources */,
|
||||||
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
|
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */,
|
||||||
);
|
);
|
||||||
@ -841,14 +849,6 @@
|
|||||||
minimumVersion = 5.0.0;
|
minimumVersion = 5.0.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
7A530B76240010D900CBFE6E /* XCRemoteSwiftPackageReference "input-mask-ios" */ = {
|
|
||||||
isa = XCRemoteSwiftPackageReference;
|
|
||||||
repositoryURL = "https://github.com/RedMadRobot/input-mask-ios";
|
|
||||||
requirement = {
|
|
||||||
kind = upToNextMajorVersion;
|
|
||||||
minimumVersion = 5.0.0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */ = {
|
7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */ = {
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/RxSwiftCommunity/RxRealm";
|
repositoryURL = "https://github.com/RxSwiftCommunity/RxRealm";
|
||||||
@ -937,11 +937,6 @@
|
|||||||
package = 7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */;
|
package = 7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */;
|
||||||
productName = RealmSwift;
|
productName = RealmSwift;
|
||||||
};
|
};
|
||||||
7A530B77240010D900CBFE6E /* InputMask */ = {
|
|
||||||
isa = XCSwiftPackageProductDependency;
|
|
||||||
package = 7A530B76240010D900CBFE6E /* XCRemoteSwiftPackageReference "input-mask-ios" */;
|
|
||||||
productName = InputMask;
|
|
||||||
};
|
|
||||||
7A530B8A240181F500CBFE6E /* RxRealm */ = {
|
7A530B8A240181F500CBFE6E /* RxRealm */ = {
|
||||||
isa = XCSwiftPackageProductDependency;
|
isa = XCSwiftPackageProductDependency;
|
||||||
package = 7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */;
|
package = 7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */;
|
||||||
|
|||||||
@ -19,22 +19,13 @@
|
|||||||
"version": "1.1.0"
|
"version": "1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"package": "InputMask",
|
|
||||||
"repositoryURL": "https://github.com/RedMadRobot/input-mask-ios",
|
|
||||||
"state": {
|
|
||||||
"branch": null,
|
|
||||||
"revision": "78a98f31d5b7fe2c0d84146748f22114c1c17c7c",
|
|
||||||
"version": "5.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"package": "Kingfisher",
|
"package": "Kingfisher",
|
||||||
"repositoryURL": "https://github.com/onevcat/Kingfisher",
|
"repositoryURL": "https://github.com/onevcat/Kingfisher",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "1339ebea9498ef6c3fc75cc195d7163d7c7167f9",
|
"revision": "175eeb4618b0a6ef4d69a7409b6a74ddd235a093",
|
||||||
"version": "5.14.1"
|
"version": "5.15.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -42,8 +33,8 @@
|
|||||||
"repositoryURL": "https://github.com/airbnb/MagazineLayout",
|
"repositoryURL": "https://github.com/airbnb/MagazineLayout",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "12dd2cc84b7f17c4f46c7d95cde64d521c588ee8",
|
"revision": "4a5eff2203ad8d8c7e14ea1b283b64f9320752a9",
|
||||||
"version": "1.6.1"
|
"version": "1.6.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -51,8 +42,8 @@
|
|||||||
"repositoryURL": "https://github.com/realm/realm-cocoa",
|
"repositoryURL": "https://github.com/realm/realm-cocoa",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "5d296d8a3750ac86e731263b44e2ba0c3c85f2cb",
|
"revision": "6310911a38d55003f0b8acca96635aa2bfc3e2c0",
|
||||||
"version": "5.3.2"
|
"version": "5.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -60,8 +51,8 @@
|
|||||||
"repositoryURL": "https://github.com/realm/realm-core",
|
"repositoryURL": "https://github.com/realm/realm-core",
|
||||||
"state": {
|
"state": {
|
||||||
"branch": null,
|
"branch": null,
|
||||||
"revision": "55a0d32516c0f3a5fd3ab8c0224ee22efcc7cd58",
|
"revision": "34d7fbcbab2a94bcad081bddf9d172961cd84659",
|
||||||
"version": "6.0.12"
|
"version": "6.0.25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
6
AutoCat/Assets.xcassets/Colors/Contents.json
Normal file
6
AutoCat/Assets.xcassets/Colors/Contents.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"platform" : "ios",
|
||||||
|
"reference" : "systemGray2Color"
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"platform" : "ios",
|
||||||
|
"reference" : "systemGray3Color"
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "1.000",
|
||||||
|
"green" : "1.000",
|
||||||
|
"red" : "1.000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "0.300",
|
||||||
|
"blue" : "1.000",
|
||||||
|
"green" : "1.000",
|
||||||
|
"red" : "1.000"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -328,14 +328,14 @@
|
|||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
<prototypes>
|
<prototypes>
|
||||||
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="VehicleCell" id="VEP-QD-i6y" customClass="VehicleCell" customModule="AutoCat" customModuleProvider="target">
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="VehicleCell" id="VEP-QD-i6y" customClass="VehicleCell" customModule="AutoCat" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="28" width="375" height="85"/>
|
<rect key="frame" x="0.0" y="28" width="375" height="85.5"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VEP-QD-i6y" id="8hH-8I-XLB">
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VEP-QD-i6y" id="8hH-8I-XLB">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="85"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="85.5"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Kia (JF) Optima" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AQY-7N-q8D">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Kia (JF) Optima" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AQY-7N-q8D">
|
||||||
<rect key="frame" x="8" y="8" width="124" height="21"/>
|
<rect key="frame" x="8" y="8" width="124" height="21.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
||||||
<nil key="textColor"/>
|
<nil key="textColor"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@ -347,7 +347,7 @@
|
|||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cvf-vM-QnT" customClass="PlateView" customModule="AutoCat" customModuleProvider="target">
|
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cvf-vM-QnT" customClass="PlateView" customModule="AutoCat" customModuleProvider="target">
|
||||||
<rect key="frame" x="8" y="37" width="317" height="40"/>
|
<rect key="frame" x="8" y="37.5" width="317" height="40"/>
|
||||||
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="height" constant="40" id="Xoz-Iw-PCU"/>
|
<constraint firstAttribute="height" constant="40" id="Xoz-Iw-PCU"/>
|
||||||
@ -596,18 +596,14 @@
|
|||||||
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="Peq-Zq-kNT">
|
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="Peq-Zq-kNT">
|
||||||
<rect key="frame" x="62.5" y="68" width="250" height="114.5"/>
|
<rect key="frame" x="62.5" y="68" width="250" height="114.5"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="A001AA 777" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8FU-Gy-4MU" customClass="CustomTextField" customModule="AutoCat" customModuleProvider="target">
|
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="A001AA 777" textAlignment="center" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="8FU-Gy-4MU" customClass="SwiftMaskTextfield" customModule="AutoCat" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="250" height="50.5"/>
|
<rect key="frame" x="0.0" y="0.0" width="250" height="50.5"/>
|
||||||
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle0"/>
|
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle0"/>
|
||||||
<textInputTraits key="textInputTraits" returnKeyType="done"/>
|
<textInputTraits key="textInputTraits" returnKeyType="done"/>
|
||||||
<userDefinedRuntimeAttributes>
|
<connections>
|
||||||
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
|
<action selector="textFieldDidBeginEditing:" destination="twc-qR-t1G" eventType="editingDidBegin" id="Kvu-xK-QuZ"/>
|
||||||
<real key="value" value="1"/>
|
<action selector="textFieldDidChange:" destination="twc-qR-t1G" eventType="editingChanged" id="x69-Ym-Zdm"/>
|
||||||
</userDefinedRuntimeAttribute>
|
</connections>
|
||||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
|
|
||||||
<real key="value" value="6"/>
|
|
||||||
</userDefinedRuntimeAttribute>
|
|
||||||
</userDefinedRuntimeAttributes>
|
|
||||||
</textField>
|
</textField>
|
||||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ync-fd-xQI" customClass="CustomButton" customModule="AutoCat" customModuleProvider="target">
|
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ync-fd-xQI" customClass="CustomButton" customModule="AutoCat" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="66.5" width="250" height="48"/>
|
<rect key="frame" x="0.0" y="66.5" width="250" height="48"/>
|
||||||
@ -696,7 +692,7 @@
|
|||||||
<connections>
|
<connections>
|
||||||
<outlet property="check" destination="Ync-fd-xQI" id="oxC-p6-Mou"/>
|
<outlet property="check" destination="Ync-fd-xQI" id="oxC-p6-Mou"/>
|
||||||
<outlet property="history" destination="JKr-UE-x8f" id="GP9-Gz-WBm"/>
|
<outlet property="history" destination="JKr-UE-x8f" id="GP9-Gz-WBm"/>
|
||||||
<outlet property="number" destination="8FU-Gy-4MU" id="cCY-vV-Mdy"/>
|
<outlet property="number" destination="8FU-Gy-4MU" id="PwP-Pn-eeO"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="h7Y-mR-2Ti" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="h7Y-mR-2Ti" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||||
@ -766,6 +762,7 @@
|
|||||||
<segue destination="RK6-pn-2Bg" kind="relationship" relationship="viewControllers" id="KNz-WF-Kyy"/>
|
<segue destination="RK6-pn-2Bg" kind="relationship" relationship="viewControllers" id="KNz-WF-Kyy"/>
|
||||||
<segue destination="GCa-Re-j14" kind="relationship" relationship="viewControllers" id="FGp-f6-fUh"/>
|
<segue destination="GCa-Re-j14" kind="relationship" relationship="viewControllers" id="FGp-f6-fUh"/>
|
||||||
<segue destination="4jU-Z3-PF2" kind="relationship" relationship="viewControllers" id="aH2-IT-86l"/>
|
<segue destination="4jU-Z3-PF2" kind="relationship" relationship="viewControllers" id="aH2-IT-86l"/>
|
||||||
|
<segue destination="5k8-Cz-8yP" kind="relationship" relationship="viewControllers" id="w22-e0-uc5"/>
|
||||||
</connections>
|
</connections>
|
||||||
</tabBarController>
|
</tabBarController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="AJs-8F-Qbu" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="AJs-8F-Qbu" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||||
@ -891,6 +888,33 @@
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="199" y="143"/>
|
<point key="canvasLocation" x="199" y="143"/>
|
||||||
</scene>
|
</scene>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="akP-Pw-M4Q">
|
||||||
|
<objects>
|
||||||
|
<viewController id="nFZ-L6-cSY" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="qu5-Ue-dlv">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<mapView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" mapType="standard" translatesAutoresizingMaskIntoConstraints="NO" id="q5m-0R-HGC">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
|
</mapView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="q5m-0R-HGC" firstAttribute="top" secondItem="qu5-Ue-dlv" secondAttribute="top" id="7pI-P3-wL4"/>
|
||||||
|
<constraint firstItem="q5m-0R-HGC" firstAttribute="leading" secondItem="qu5-Ue-dlv" secondAttribute="leading" id="P1e-Ua-97P"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="q5m-0R-HGC" secondAttribute="bottom" id="rrd-Z6-g8h"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="q5m-0R-HGC" secondAttribute="trailing" id="s5w-az-6e7"/>
|
||||||
|
</constraints>
|
||||||
|
<viewLayoutGuide key="safeArea" id="gve-eU-fKS"/>
|
||||||
|
</view>
|
||||||
|
<navigationItem key="navigationItem" id="jf2-Du-fcn"/>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="XB6-0a-b8N" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="4200.8000000000002" y="-1374.0629685157423"/>
|
||||||
|
</scene>
|
||||||
<!--Check-->
|
<!--Check-->
|
||||||
<scene sceneID="pUX-kf-oY1">
|
<scene sceneID="pUX-kf-oY1">
|
||||||
<objects>
|
<objects>
|
||||||
@ -966,12 +990,32 @@
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="3261.5999999999999" y="1660.1199400299852"/>
|
<point key="canvasLocation" x="3261.5999999999999" y="1660.1199400299852"/>
|
||||||
</scene>
|
</scene>
|
||||||
|
<!--Map-->
|
||||||
|
<scene sceneID="XqL-ef-b4J">
|
||||||
|
<objects>
|
||||||
|
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="5k8-Cz-8yP" sceneMemberID="viewController">
|
||||||
|
<tabBarItem key="tabBarItem" title="Map" image="map" catalog="system" id="emU-RO-5HQ"/>
|
||||||
|
<toolbarItems/>
|
||||||
|
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="0UP-PJ-Rc3">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
</navigationBar>
|
||||||
|
<nil name="viewControllers"/>
|
||||||
|
<connections>
|
||||||
|
<segue destination="nFZ-L6-cSY" kind="relationship" relationship="rootViewController" id="iQf-3h-ziw"/>
|
||||||
|
</connections>
|
||||||
|
</navigationController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="THp-Fz-ftx" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="3261.5999999999999" y="-1374.0629685157423"/>
|
||||||
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="check" width="25" height="25"/>
|
<image name="check" width="25" height="25"/>
|
||||||
<image name="check-compact" width="18" height="18"/>
|
<image name="check-compact" width="18" height="18"/>
|
||||||
<image name="doc.on.doc" catalog="system" width="117" height="128"/>
|
<image name="doc.on.doc" catalog="system" width="117" height="128"/>
|
||||||
<image name="line.horizontal.3.decrease" catalog="system" width="128" height="73"/>
|
<image name="line.horizontal.3.decrease" catalog="system" width="128" height="73"/>
|
||||||
|
<image name="map" catalog="system" width="128" height="113"/>
|
||||||
<image name="play.fill" catalog="system" width="116" height="128"/>
|
<image name="play.fill" catalog="system" width="116" height="128"/>
|
||||||
<image name="record" width="31" height="31"/>
|
<image name="record" width="31" height="31"/>
|
||||||
<image name="record-compact" width="23" height="23"/>
|
<image name="record-compact" width="23" height="23"/>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import InputMask
|
|
||||||
import RealmSwift
|
import RealmSwift
|
||||||
import RxSwift
|
import RxSwift
|
||||||
import SwiftDate
|
import SwiftDate
|
||||||
@ -12,14 +11,13 @@ enum EventAction {
|
|||||||
case sendSpecific(VehicleEvent)
|
case sendSpecific(VehicleEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
class CheckController: UIViewController, MaskedTextFieldDelegateListener, UITableViewDelegate {
|
class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegate, PNKeyboardDelegate {
|
||||||
|
|
||||||
@IBOutlet weak var number: UITextField!
|
@IBOutlet weak var number: SwiftMaskTextfield!
|
||||||
@IBOutlet weak var check: UIButton!
|
@IBOutlet weak var check: UIButton!
|
||||||
@IBOutlet weak var history: UITableView!
|
@IBOutlet weak var history: UITableView!
|
||||||
|
|
||||||
let bag = DisposeBag()
|
let bag = DisposeBag()
|
||||||
let maskFieldDelegate = MaskedTextFieldDelegate()
|
|
||||||
|
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
|
|
||||||
@ -29,9 +27,10 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener, UITabl
|
|||||||
guard let realm = try? Realm() else { return }
|
guard let realm = try? Realm() else { return }
|
||||||
|
|
||||||
self.hideKeyboardWhenTappedAround()
|
self.hideKeyboardWhenTappedAround()
|
||||||
self.maskFieldDelegate.primaryMaskFormat = "[A][000][AA] [009]"
|
let keyboard = PNKeyboard(target: self.number)
|
||||||
self.maskFieldDelegate.listener = self
|
keyboard.delegate = self
|
||||||
self.number.delegate = self.maskFieldDelegate
|
self.number.formatPattern = "@###@@###"
|
||||||
|
self.number.inputView = keyboard
|
||||||
self.check.isEnabled = false
|
self.check.isEnabled = false
|
||||||
|
|
||||||
let ds = RxTableViewSectionedAnimatedDataSource<DateSection<Vehicle>>(configureCell: { dataSource, tableView, indexPath, item in
|
let ds = RxTableViewSectionedAnimatedDataSource<DateSection<Vehicle>>(configureCell: { dataSource, tableView, indexPath, item in
|
||||||
@ -211,19 +210,25 @@ class CheckController: UIViewController, MaskedTextFieldDelegateListener, UITabl
|
|||||||
|
|
||||||
// MARK: - UITextFieldDelegate
|
// MARK: - UITextFieldDelegate
|
||||||
|
|
||||||
func textField(_ textField: UITextField, didFillMandatoryCharacters complete: Bool, didExtractValue value: String) {
|
@IBAction func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||||
self.check.isEnabled = complete
|
LocationManager.requestCurrentLocation().subscribe().disposed(by: self.bag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
@IBAction func textFieldDidChange(_ textField: UITextField) {
|
||||||
|
guard let text = textField.text else {
|
||||||
|
self.check.isEnabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.check.isEnabled = text.count >= 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - PNKeyboardDelegate
|
||||||
|
|
||||||
|
func returnClicked() {
|
||||||
if self.check.isEnabled {
|
if self.check.isEnabled {
|
||||||
self.checkTapped(self.check)
|
self.checkTapped(self.check)
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
|
||||||
LocationManager.requestCurrentLocation().subscribe().disposed(by: self.bag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: -
|
// MARK: -
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class RecordsController: UIViewController, UITableViewDelegate {
|
|||||||
var recordDisposable: Disposable?
|
var recordDisposable: Disposable?
|
||||||
var audioSessionObserver: NSObjectProtocol?
|
var audioSessionObserver: NSObjectProtocol?
|
||||||
|
|
||||||
let validLetters = ["А", "В", "Е", "К", "М", "Н", "О", "Р", "С", "Т", "У", "Х"]
|
let validLetters = Constants.pnLettersMap.keys.map(String.init)
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|||||||
BIN
AutoCat/Fonts/RoadNumbers.otf
Normal file
BIN
AutoCat/Fonts/RoadNumbers.otf
Normal file
Binary file not shown.
@ -52,6 +52,7 @@
|
|||||||
<string>Access is needed for recognizing plate numbers from voice recordings</string>
|
<string>Access is needed for recognizing plate numbers from voice recordings</string>
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
|
<string>RoadNumbers.otf</string>
|
||||||
<string>RoadNumbers2.0.otf</string>
|
<string>RoadNumbers2.0.otf</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UIApplicationSceneManifest</key>
|
<key>UIApplicationSceneManifest</key>
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
class PlateNumber {
|
class PlateNumber {
|
||||||
private static let lettersMap: [Character: Character] = [
|
|
||||||
"А": "A", "В": "B", "Е": "E", "К": "K", "М": "M", "Н": "H", "О": "O", "Р": "P", "С": "C", "Т": "T", "У": "Y", "Х": "X"
|
|
||||||
]
|
|
||||||
|
|
||||||
private var number: String
|
private var number: String
|
||||||
private var numberEnglish: String
|
private var numberEnglish: String
|
||||||
|
|
||||||
init(_ string: String) {
|
init(_ string: String) {
|
||||||
self.number = string
|
self.number = string
|
||||||
self.numberEnglish = String(self.number.map { PlateNumber.lettersMap[$0] ?? $0 })
|
self.numberEnglish = String(self.number.map { Constants.pnLettersMap[$0] ?? $0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
func asString() -> String {
|
func asString() -> String {
|
||||||
@ -18,12 +14,12 @@ class PlateNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mainPart() -> String {
|
func mainPart() -> String {
|
||||||
let index = self.numberEnglish.startIndex(offsetBy: 6)
|
let index = self.numberEnglish.index(self.numberEnglish.startIndex, offsetBy: 6)
|
||||||
return String(self.numberEnglish[..<index])
|
return String(self.numberEnglish[..<index])
|
||||||
}
|
}
|
||||||
|
|
||||||
func region() -> String {
|
func region() -> String {
|
||||||
let index = self.numberEnglish.startIndex(offsetBy: 6)
|
let index = self.numberEnglish.index(self.numberEnglish.startIndex, offsetBy: 6)
|
||||||
return String(self.numberEnglish[index...])
|
return String(self.numberEnglish[index...])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
269
AutoCat/ThirdParty/SwiftMaskTextfield.swift
vendored
Normal file
269
AutoCat/ThirdParty/SwiftMaskTextfield.swift
vendored
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
* MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 Gabriel Maccori Kozma
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
//**********************************************************************************************************
|
||||||
|
//
|
||||||
|
// MARK: - Constants -
|
||||||
|
//
|
||||||
|
//**********************************************************************************************************
|
||||||
|
|
||||||
|
//**********************************************************************************************************
|
||||||
|
//
|
||||||
|
// MARK: - Definitions -
|
||||||
|
//
|
||||||
|
//**********************************************************************************************************
|
||||||
|
|
||||||
|
//**********************************************************************************************************
|
||||||
|
//
|
||||||
|
// MARK: - Class -
|
||||||
|
//
|
||||||
|
//**********************************************************************************************************
|
||||||
|
|
||||||
|
open class SwiftMaskTextfield : UITextField {
|
||||||
|
|
||||||
|
//**************************************************
|
||||||
|
// MARK: - Properties
|
||||||
|
//**************************************************
|
||||||
|
|
||||||
|
public let lettersAndDigitsReplacementChar: String = "*"
|
||||||
|
public let anyLetterReplecementChar: String = "@"
|
||||||
|
public let lowerCaseLetterReplecementChar: String = "a"
|
||||||
|
public let upperCaseLetterReplecementChar: String = "A"
|
||||||
|
public let digitsReplecementChar: String = "#"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Var that holds the format pattern that you wish to apply
|
||||||
|
to some text
|
||||||
|
|
||||||
|
If the pattern is set to "" no mask would be applied and
|
||||||
|
the textfield would behave like a normal one
|
||||||
|
*/
|
||||||
|
@IBInspectable open var formatPattern: String = ""
|
||||||
|
|
||||||
|
/**
|
||||||
|
Var that holds the prefix to be added to the textfield
|
||||||
|
|
||||||
|
If the prefix is set to "" no string will be added to the beggining
|
||||||
|
of the text
|
||||||
|
*/
|
||||||
|
@IBInspectable open var prefix: String = ""
|
||||||
|
|
||||||
|
/**
|
||||||
|
Var that have the maximum length, based on the mask set
|
||||||
|
*/
|
||||||
|
open var maxLength: Int {
|
||||||
|
get {
|
||||||
|
return formatPattern.count + prefix.count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Overriding the var text from UITextField so if any text
|
||||||
|
is applied programmatically by calling formatText
|
||||||
|
*/
|
||||||
|
override open var text: String? {
|
||||||
|
set {
|
||||||
|
super.text = newValue
|
||||||
|
self.formatText()
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
return super.text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//**************************************************
|
||||||
|
// MARK: - Constructors
|
||||||
|
//**************************************************
|
||||||
|
|
||||||
|
public required init?(coder aDecoder: NSCoder) {
|
||||||
|
super.init(coder: aDecoder)
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
public override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.deRegisterForNotifications()
|
||||||
|
}
|
||||||
|
|
||||||
|
//**************************************************
|
||||||
|
// MARK: - Private Methods
|
||||||
|
//**************************************************
|
||||||
|
|
||||||
|
fileprivate func setup() {
|
||||||
|
self.registerForNotifications()
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func registerForNotifications() {
|
||||||
|
NotificationCenter.default.addObserver(self,
|
||||||
|
selector: #selector(textDidChange),
|
||||||
|
name: NSNotification.Name(rawValue: "UITextFieldTextDidChangeNotification"),
|
||||||
|
object: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func deRegisterForNotifications() {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc fileprivate func textDidChange() {
|
||||||
|
self.undoManager?.removeAllActions()
|
||||||
|
self.formatText()
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func getOnlyDigitsString(_ string: String) -> String {
|
||||||
|
let charactersArray = string.components(separatedBy: CharacterSet.decimalDigits.inverted)
|
||||||
|
return charactersArray.joined(separator: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func getOnlyLettersString(_ string: String) -> String {
|
||||||
|
let charactersArray = string.components(separatedBy: CharacterSet.letters.inverted)
|
||||||
|
return charactersArray.joined(separator: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func getUppercaseLettersString(_ string: String) -> String {
|
||||||
|
let charactersArray = string.components(separatedBy: CharacterSet.uppercaseLetters.inverted)
|
||||||
|
return charactersArray.joined(separator: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func getLowercaseLettersString(_ string: String) -> String {
|
||||||
|
let charactersArray = string.components(separatedBy: CharacterSet.lowercaseLetters.inverted)
|
||||||
|
return charactersArray.joined(separator: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func getFilteredString(_ string: String) -> String {
|
||||||
|
let charactersArray = string.components(separatedBy: CharacterSet.alphanumerics.inverted)
|
||||||
|
return charactersArray.joined(separator: "")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate func getStringWithoutPrefix(_ string: String) -> String {
|
||||||
|
if string.range(of: self.prefix) != nil {
|
||||||
|
if string.count > self.prefix.count {
|
||||||
|
let prefixIndex = string.index(string.endIndex, offsetBy: (string.count - self.prefix.count) * -1)
|
||||||
|
return String(string[prefixIndex...])
|
||||||
|
} else if string.count == self.prefix.count {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return string
|
||||||
|
}
|
||||||
|
|
||||||
|
//**************************************************
|
||||||
|
// MARK: - Self Public Methods
|
||||||
|
//**************************************************
|
||||||
|
|
||||||
|
/**
|
||||||
|
Func that formats the text based on formatPattern
|
||||||
|
|
||||||
|
Override this function if you want to customize the behaviour of
|
||||||
|
the class
|
||||||
|
*/
|
||||||
|
open func formatText() {
|
||||||
|
var currentTextForFormatting = ""
|
||||||
|
|
||||||
|
if let text = super.text {
|
||||||
|
if text.count > 0 {
|
||||||
|
currentTextForFormatting = self.getStringWithoutPrefix(text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.maxLength > 0 {
|
||||||
|
var formatterIndex = self.formatPattern.startIndex, currentTextForFormattingIndex = currentTextForFormatting.startIndex
|
||||||
|
var finalText = ""
|
||||||
|
|
||||||
|
currentTextForFormatting = self.getFilteredString(currentTextForFormatting)
|
||||||
|
|
||||||
|
if currentTextForFormatting.count > 0 {
|
||||||
|
while true {
|
||||||
|
let formatPatternRange = formatterIndex ..< formatPattern.index(after: formatterIndex)
|
||||||
|
let currentFormatCharacter = String(self.formatPattern[formatPatternRange])
|
||||||
|
|
||||||
|
let currentTextForFormattingPatterRange = currentTextForFormattingIndex ..< currentTextForFormatting.index(after: currentTextForFormattingIndex)
|
||||||
|
let currentTextForFormattingCharacter = String(currentTextForFormatting[currentTextForFormattingPatterRange])
|
||||||
|
|
||||||
|
switch currentFormatCharacter {
|
||||||
|
case self.lettersAndDigitsReplacementChar:
|
||||||
|
finalText += currentTextForFormattingCharacter
|
||||||
|
currentTextForFormattingIndex = currentTextForFormatting.index(after: currentTextForFormattingIndex)
|
||||||
|
formatterIndex = formatPattern.index(after: formatterIndex)
|
||||||
|
case self.anyLetterReplecementChar:
|
||||||
|
let filteredChar = self.getOnlyLettersString(currentTextForFormattingCharacter)
|
||||||
|
if !filteredChar.isEmpty {
|
||||||
|
finalText += filteredChar
|
||||||
|
formatterIndex = formatPattern.index(after: formatterIndex)
|
||||||
|
}
|
||||||
|
currentTextForFormattingIndex = currentTextForFormatting.index(after: currentTextForFormattingIndex)
|
||||||
|
case self.lowerCaseLetterReplecementChar:
|
||||||
|
let filteredChar = self.getLowercaseLettersString(currentTextForFormattingCharacter)
|
||||||
|
if !filteredChar.isEmpty {
|
||||||
|
finalText += filteredChar
|
||||||
|
formatterIndex = formatPattern.index(after: formatterIndex)
|
||||||
|
}
|
||||||
|
currentTextForFormattingIndex = currentTextForFormatting.index(after: currentTextForFormattingIndex)
|
||||||
|
case self.upperCaseLetterReplecementChar:
|
||||||
|
let filteredChar = self.getUppercaseLettersString(currentTextForFormattingCharacter)
|
||||||
|
if !filteredChar.isEmpty {
|
||||||
|
finalText += filteredChar
|
||||||
|
formatterIndex = formatPattern.index(after: formatterIndex)
|
||||||
|
}
|
||||||
|
currentTextForFormattingIndex = currentTextForFormatting.index(after: currentTextForFormattingIndex)
|
||||||
|
case self.digitsReplecementChar:
|
||||||
|
let filteredChar = self.getOnlyDigitsString(currentTextForFormattingCharacter)
|
||||||
|
if !filteredChar.isEmpty {
|
||||||
|
finalText += filteredChar
|
||||||
|
formatterIndex = formatPattern.index(after: formatterIndex)
|
||||||
|
}
|
||||||
|
currentTextForFormattingIndex = currentTextForFormatting.index(after: currentTextForFormattingIndex)
|
||||||
|
default:
|
||||||
|
finalText += currentFormatCharacter
|
||||||
|
formatterIndex = formatPattern.index(after: formatterIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
if formatterIndex >= self.formatPattern.endIndex ||
|
||||||
|
currentTextForFormattingIndex >= currentTextForFormatting.endIndex {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if finalText.count > 0 {
|
||||||
|
super.text = "\(self.prefix)\(finalText)"
|
||||||
|
} else {
|
||||||
|
super.text = finalText
|
||||||
|
}
|
||||||
|
|
||||||
|
if let text = self.text {
|
||||||
|
if text.count > self.maxLength {
|
||||||
|
super.text = String(text[text.index(text.startIndex, offsetBy: self.maxLength)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,14 +3,18 @@ import Foundation
|
|||||||
enum Constants {
|
enum Constants {
|
||||||
static var baseUrl: String {
|
static var baseUrl: String {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
return "http://127.0.0.1:3000/"
|
//return "http://127.0.0.1:3000/"
|
||||||
//return "http://192.168.1.67:3000/"
|
//return "http://192.168.1.67:3000/"
|
||||||
//return "https://vps.aliencat.pro:8443/"
|
return "https://vps.aliencat.pro:8443/"
|
||||||
#else
|
#else
|
||||||
return "https://vps.aliencat.pro:8443/"
|
return "https://vps.aliencat.pro:8443/"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static let pnLettersMap: [Character: Character] = [
|
||||||
|
"А": "A", "В": "B", "Е": "E", "К": "K", "М": "M", "Н": "H", "О": "O", "Р": "P", "С": "C", "Т": "T", "У": "Y", "Х": "X"
|
||||||
|
]
|
||||||
|
|
||||||
static let googleAuthURL = "https://accounts.google.com/o/oauth2/v2/auth"
|
static let googleAuthURL = "https://accounts.google.com/o/oauth2/v2/auth"
|
||||||
static let googleTokenURL = "https://oauth2.googleapis.com/token"
|
static let googleTokenURL = "https://oauth2.googleapis.com/token"
|
||||||
static let googleRedirectURL = "com.googleusercontent.apps.994679674451-k7clunkk4nicl6iuajdtc5u7hvustbdb:/oauth2callback"
|
static let googleRedirectURL = "com.googleusercontent.apps.994679674451-k7clunkk4nicl6iuajdtc5u7hvustbdb:/oauth2callback"
|
||||||
|
|||||||
201
AutoCat/Views/PNKeyboard.swift
Normal file
201
AutoCat/Views/PNKeyboard.swift
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
import UIKit
|
||||||
|
|
||||||
|
protocol PNKeyboardDelegate: class {
|
||||||
|
func returnClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
protocol PNButtonDelegate: class {
|
||||||
|
func buttonTapped(_ button: PNButton)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PNButtonType {
|
||||||
|
case symbol(String)
|
||||||
|
case backspace
|
||||||
|
case done
|
||||||
|
}
|
||||||
|
|
||||||
|
class PNButton: UIButton {
|
||||||
|
private(set) var type: PNButtonType
|
||||||
|
private var timer: Timer?
|
||||||
|
private var waitCount = 0
|
||||||
|
|
||||||
|
weak var delegate: PNButtonDelegate?
|
||||||
|
|
||||||
|
init(letter: Character) {
|
||||||
|
self.type = .symbol(String(letter))
|
||||||
|
super.init(frame: .zero)
|
||||||
|
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)
|
||||||
|
self.backgroundColor = UIColor(named: "KeyBackground")
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(digit: Int) {
|
||||||
|
self.type = .symbol(String(digit))
|
||||||
|
super.init(frame: .zero)
|
||||||
|
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)
|
||||||
|
self.setTitleColor(.label, for: .normal)
|
||||||
|
self.backgroundColor = UIColor(named: "KeyBackground")
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
init(imageName: String, type: PNButtonType) {
|
||||||
|
self.type = type
|
||||||
|
super.init(frame: .zero)
|
||||||
|
self.setImage(UIImage(systemName: imageName), for: .normal)
|
||||||
|
self.backgroundColor = UIColor(named: "DarkKeyBackground")
|
||||||
|
self.tintColor = .label
|
||||||
|
self.setup()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup(_ radius: CGFloat = 0.5) {
|
||||||
|
self.layer.cornerRadius = 6
|
||||||
|
self.layer.shadowColor = UIColor.black.cgColor
|
||||||
|
self.layer.shadowOpacity = 0.4
|
||||||
|
self.layer.shadowOffset = CGSize(width: 0.0, height : 1.0)
|
||||||
|
self.layer.shadowRadius = radius
|
||||||
|
|
||||||
|
self.addTarget(self, action: #selector(buttonDown), for: .touchDown)
|
||||||
|
self.addTarget(self, action: #selector(buttonUp), for: [.touchUpInside, .touchUpOutside])
|
||||||
|
self.addTarget(self, action: #selector(touchUpInside), for: .touchUpInside)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func buttonDown(_ sender: PNButton) {
|
||||||
|
print("buttonDown")
|
||||||
|
sender.layer.opacity = 0.3
|
||||||
|
self.timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in
|
||||||
|
self.waitCount += 1
|
||||||
|
if self.waitCount > 5 {
|
||||||
|
self.delegate?.buttonTapped(self)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func buttonUp(_ sender: PNButton) {
|
||||||
|
print("buttonUp")
|
||||||
|
sender.layer.opacity = 1
|
||||||
|
self.timer?.invalidate()
|
||||||
|
self.timer = nil
|
||||||
|
self.waitCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func touchUpInside(_ sender: PNButton) {
|
||||||
|
print("touchUpInside")
|
||||||
|
self.delegate?.buttonTapped(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
|
||||||
|
private weak var target: UIKeyInput?
|
||||||
|
weak var delegate: PNKeyboardDelegate?
|
||||||
|
|
||||||
|
init(target: UIKeyInput) {
|
||||||
|
self.target = target
|
||||||
|
super.init(frame: .zero)
|
||||||
|
self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
|
|
||||||
|
let blurEffectView = UIVisualEffectView(effect: UIBlurEffect())
|
||||||
|
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
||||||
|
self.addSubview(blurEffectView)
|
||||||
|
|
||||||
|
self.setupButtons()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupButtons() {
|
||||||
|
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)
|
||||||
|
button.delegate = self
|
||||||
|
return button
|
||||||
|
}
|
||||||
|
let backspace = PNButton(imageName: "delete.left", type: .backspace)
|
||||||
|
backspace.delegate = self
|
||||||
|
|
||||||
|
let done = PNButton(imageName: "arrow.turn.down.left", type: .done)
|
||||||
|
done.delegate = self
|
||||||
|
done.backgroundColor = .systemBlue
|
||||||
|
done.tintColor = .white
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
let digitRows = [
|
||||||
|
self.createLetterStack([digits[0], digits[1], digits[2]]),
|
||||||
|
self.createLetterStack([digits[3], digits[4], digits[5]]),
|
||||||
|
self.createLetterStack([digits[6], digits[7], digits[8]]),
|
||||||
|
self.createLetterStack([digits[9], backspace, done])
|
||||||
|
]
|
||||||
|
|
||||||
|
let digitsStack = UIStackView(arrangedSubviews: digitRows)
|
||||||
|
digitsStack.axis = .vertical
|
||||||
|
digitsStack.distribution = .fillEqually
|
||||||
|
digitsStack.spacing = 8
|
||||||
|
|
||||||
|
let mainStack = UIStackView(arrangedSubviews: [lettersStack, digitsStack])
|
||||||
|
mainStack.spacing = 16
|
||||||
|
mainStack.distribution = .fillEqually
|
||||||
|
mainStack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
self.addSubview(mainStack)
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
mainStack.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 16),
|
||||||
|
mainStack.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -16),
|
||||||
|
mainStack.topAnchor.constraint(equalTo: self.topAnchor, constant: 16),
|
||||||
|
mainStack.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: -16)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
func createLetterStack(_ views: [UIView]) -> UIStackView {
|
||||||
|
let stack = UIStackView(arrangedSubviews: views)
|
||||||
|
stack.distribution = .fillEqually
|
||||||
|
stack.spacing = 8
|
||||||
|
return stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - PNButtonDelegate
|
||||||
|
|
||||||
|
func buttonTapped(_ button: PNButton) {
|
||||||
|
UIDevice.current.playInputClick()
|
||||||
|
|
||||||
|
switch button.type {
|
||||||
|
case .symbol(let s):
|
||||||
|
self.target?.insertText(s)
|
||||||
|
case .backspace:
|
||||||
|
self.target?.deleteBackward()
|
||||||
|
case .done:
|
||||||
|
self.delegate?.returnClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - UIInputViewAudioFeedback
|
||||||
|
|
||||||
|
var enableInputClicksWhenVisible: Bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user