Adding number with puller instead of old textfield

This commit is contained in:
Selim Mustafaev 2023-01-08 16:22:07 +03:00
parent 512a50b217
commit 1d377b8faa
24 changed files with 624 additions and 252 deletions

View File

@ -84,6 +84,14 @@
7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */; }; 7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */; };
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8B2435C38700258F61 /* CustomTextField.swift */; }; 7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8B2435C38700258F61 /* CustomTextField.swift */; };
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; }; 7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; };
7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7AC355492969652F00889457 /* SwiftEntryKit */; };
7AC3554C29696A1C00889457 /* MainTabController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3554B29696A1C00889457 /* MainTabController.swift */; };
7AC3554E29696C4500889457 /* DummyNewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3554D29696C4500889457 /* DummyNewController.swift */; };
7AC3555029696D5A00889457 /* NewNumberController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3554F29696D5A00889457 /* NewNumberController.swift */; };
7AC3555229696E3F00889457 /* UIView+layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3555129696E3F00889457 /* UIView+layout.swift */; };
7AC35554296973E100889457 /* ACButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC35553296973E100889457 /* ACButton.swift */; };
7AC355592969746600889457 /* UIControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC355582969746600889457 /* UIControl.swift */; };
7AC3555B296995B200889457 /* UIEdgeInsets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC3555A296995B200889457 /* UIEdgeInsets.swift */; };
7AC76D7B270083AE0084DB27 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC76D7A270083AE0084DB27 /* TextView.swift */; }; 7AC76D7B270083AE0084DB27 /* TextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AC76D7A270083AE0084DB27 /* TextView.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 */; };
@ -251,6 +259,13 @@
7AB562B9249C9E9B00473D53 /* VehicleRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleRegion.swift; sourceTree = "<group>"; }; 7AB562B9249C9E9B00473D53 /* VehicleRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleRegion.swift; sourceTree = "<group>"; };
7AB67E8B2435C38700258F61 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; }; 7AB67E8B2435C38700258F61 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
7AB67E8D2435D1A000258F61 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; }; 7AB67E8D2435D1A000258F61 /* CustomButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomButton.swift; sourceTree = "<group>"; };
7AC3554B29696A1C00889457 /* MainTabController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainTabController.swift; sourceTree = "<group>"; };
7AC3554D29696C4500889457 /* DummyNewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DummyNewController.swift; sourceTree = "<group>"; };
7AC3554F29696D5A00889457 /* NewNumberController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewNumberController.swift; sourceTree = "<group>"; };
7AC3555129696E3F00889457 /* UIView+layout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+layout.swift"; sourceTree = "<group>"; };
7AC35553296973E100889457 /* ACButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACButton.swift; sourceTree = "<group>"; };
7AC355582969746600889457 /* UIControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControl.swift; sourceTree = "<group>"; };
7AC3555A296995B200889457 /* UIEdgeInsets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIEdgeInsets.swift; sourceTree = "<group>"; };
7AC76D7A270083AE0084DB27 /* TextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextView.swift; sourceTree = "<group>"; }; 7AC76D7A270083AE0084DB27 /* TextView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextView.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>"; };
@ -285,6 +300,7 @@
7AA7BC3325A5DFB80053A5D5 /* Kingfisher in Frameworks */, 7AA7BC3325A5DFB80053A5D5 /* Kingfisher in Frameworks */,
7A813DBE2506A57100CC93B9 /* AuthenticationServices.framework in Frameworks */, 7A813DBE2506A57100CC93B9 /* AuthenticationServices.framework in Frameworks */,
7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */, 7AA7BC3625A5DFB80053A5D5 /* PKHUD in Frameworks */,
7AC3554A2969652F00889457 /* SwiftEntryKit in Frameworks */,
7AF6D2042677C03B0086EA64 /* AutoCatCore.framework in Frameworks */, 7AF6D2042677C03B0086EA64 /* AutoCatCore.framework in Frameworks */,
7A35177B27E23F8800DC538C /* Eureka in Frameworks */, 7A35177B27E23F8800DC538C /* Eureka in Frameworks */,
7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */, 7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */,
@ -368,6 +384,7 @@
7A1146FF23FDE7E500B424AF /* AutoCat */ = { 7A1146FF23FDE7E500B424AF /* AutoCat */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
7AC355552969742800889457 /* ACUIKit */,
7A530B7C24017FBE00CBFE6E /* Cells */, 7A530B7C24017FBE00CBFE6E /* Cells */,
7A11471423FDEAF800B424AF /* Controllers */, 7A11471423FDEAF800B424AF /* Controllers */,
7A3F07A924360D9100E59687 /* Extensions */, 7A3F07A924360D9100E59687 /* Extensions */,
@ -408,6 +425,9 @@
7A3F07AC2436350B00E59687 /* SearchController.swift */, 7A3F07AC2436350B00E59687 /* SearchController.swift */,
7AEFE727240455E200910EB7 /* SettingsController.swift */, 7AEFE727240455E200910EB7 /* SettingsController.swift */,
7A6F095D26DB9F85003A965D /* NotesController.swift */, 7A6F095D26DB9F85003A965D /* NotesController.swift */,
7AC3554B29696A1C00889457 /* MainTabController.swift */,
7AC3554D29696C4500889457 /* DummyNewController.swift */,
7AC3554F29696D5A00889457 /* NewNumberController.swift */,
); );
path = Controllers; path = Controllers;
sourceTree = "<group>"; sourceTree = "<group>";
@ -558,6 +578,33 @@
path = Location; path = Location;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
7AC355552969742800889457 /* ACUIKit */ = {
isa = PBXGroup;
children = (
7AC355562969743800889457 /* Views */,
7AC355572969744100889457 /* Extensions */,
);
path = ACUIKit;
sourceTree = "<group>";
};
7AC355562969743800889457 /* Views */ = {
isa = PBXGroup;
children = (
7AC35553296973E100889457 /* ACButton.swift */,
);
path = Views;
sourceTree = "<group>";
};
7AC355572969744100889457 /* Extensions */ = {
isa = PBXGroup;
children = (
7AC3555129696E3F00889457 /* UIView+layout.swift */,
7AC355582969746600889457 /* UIControl.swift */,
7AC3555A296995B200889457 /* UIEdgeInsets.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
7AF6D1DE2677A7E00086EA64 /* AutoCatTests */ = { 7AF6D1DE2677A7E00086EA64 /* AutoCatTests */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -642,6 +689,7 @@
7A813DC02508C4D900CC93B9 /* ExceptionCatcher */, 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */,
7AABDE1C2532F3EB0041AFC6 /* PKHUD */, 7AABDE1C2532F3EB0041AFC6 /* PKHUD */,
7A35177A27E23F8800DC538C /* Eureka */, 7A35177A27E23F8800DC538C /* Eureka */,
7AC355492969652F00889457 /* SwiftEntryKit */,
); );
productName = AutoCat; productName = AutoCat;
productReference = 7A1146FD23FDE7E500B424AF /* AutoCat.app */; productReference = 7A1146FD23FDE7E500B424AF /* AutoCat.app */;
@ -734,6 +782,7 @@
7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */, 7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */,
7AABDE21253327F10041AFC6 /* XCRemoteSwiftPackageReference "DifferenceKit" */, 7AABDE21253327F10041AFC6 /* XCRemoteSwiftPackageReference "DifferenceKit" */,
7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */, 7A35177927E23F8800DC538C /* XCRemoteSwiftPackageReference "Eureka" */,
7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */,
); );
productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */; productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */;
projectDirPath = ""; projectDirPath = "";
@ -792,12 +841,14 @@
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */, 7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */,
7A99406426E4BFAE002E9CB6 /* VehicleNoteCell.swift in Sources */, 7A99406426E4BFAE002E9CB6 /* VehicleNoteCell.swift in Sources */,
7A8AB76B25A1D95500ECF2C1 /* SourceStatusRow.swift in Sources */, 7A8AB76B25A1D95500ECF2C1 /* SourceStatusRow.swift in Sources */,
7AC3554C29696A1C00889457 /* MainTabController.swift in Sources */,
7A813DC32508EE4F00CC93B9 /* EventCell.swift in Sources */, 7A813DC32508EE4F00CC93B9 /* EventCell.swift in Sources */,
7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */, 7A3F07AD2436350B00E59687 /* SearchController.swift in Sources */,
7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */, 7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */,
7A0B96A0257D6D4B000B39AD /* MultilineLabelRow.swift in Sources */, 7A0B96A0257D6D4B000B39AD /* MultilineLabelRow.swift in Sources */,
7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */, 7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */,
7A761C0B267E8FF90005F28F /* Error.swift in Sources */, 7A761C0B267E8FF90005F28F /* Error.swift in Sources */,
7AC3555029696D5A00889457 /* NewNumberController.swift in Sources */,
7AE26A3524F31B0700625033 /* EventsController.swift in Sources */, 7AE26A3524F31B0700625033 /* EventsController.swift in Sources */,
7A2DE69E2589606A00A113FC /* ImageGridRow.swift in Sources */, 7A2DE69E2589606A00A113FC /* ImageGridRow.swift in Sources */,
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */, 7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */,
@ -808,6 +859,7 @@
7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */, 7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */,
7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */, 7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */,
7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */, 7ADF6CA12512244400F237B2 /* MapExt.swift in Sources */,
7AC3554E29696C4500889457 /* DummyNewController.swift in Sources */,
7A659B5B24A3768A0043A0F2 /* Substrings.swift in Sources */, 7A659B5B24A3768A0043A0F2 /* Substrings.swift in Sources */,
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */, 7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */,
7A27ADF7249FEF690035F39E /* Recorder.swift in Sources */, 7A27ADF7249FEF690035F39E /* Recorder.swift in Sources */,
@ -836,10 +888,14 @@
7A813DCB250B5DC900CC93B9 /* LocationPickerController.swift in Sources */, 7A813DCB250B5DC900CC93B9 /* LocationPickerController.swift in Sources */,
7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */, 7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */,
7A8AB76525A0DB8F00ECF2C1 /* BundleVersion.swift in Sources */, 7A8AB76525A0DB8F00ECF2C1 /* BundleVersion.swift in Sources */,
7AC3555229696E3F00889457 /* UIView+layout.swift in Sources */,
7A0420AD2561A0B100034941 /* OsagoController.swift in Sources */, 7A0420AD2561A0B100034941 /* OsagoController.swift in Sources */,
7AC355592969746600889457 /* UIControl.swift in Sources */,
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */, 7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */,
7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */, 7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */,
7AC35554296973E100889457 /* ACButton.swift in Sources */,
7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */, 7A8A220B248D67B60073DFD9 /* VehicleReportImage.swift in Sources */,
7AC3555B296995B200889457 /* UIEdgeInsets.swift in Sources */,
7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */, 7ADF6C95250D037700F237B2 /* ShowEventController.swift in Sources */,
7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */, 7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */,
7AE492A1259232F000322D2E /* MultilineLinkRow.swift in Sources */, 7AE492A1259232F000322D2E /* MultilineLinkRow.swift in Sources */,
@ -1080,7 +1136,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements; CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 100; CURRENT_PROJECT_VERSION = 101;
DEVELOPMENT_TEAM = 46DTTB8X4S; DEVELOPMENT_TEAM = 46DTTB8X4S;
INFOPLIST_FILE = AutoCat/Info.plist; INFOPLIST_FILE = AutoCat/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@ -1105,7 +1161,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements; CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 100; CURRENT_PROJECT_VERSION = 101;
DEVELOPMENT_TEAM = 46DTTB8X4S; DEVELOPMENT_TEAM = 46DTTB8X4S;
INFOPLIST_FILE = AutoCat/Info.plist; INFOPLIST_FILE = AutoCat/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 13.0;
@ -1329,6 +1385,14 @@
minimumVersion = 1.1.5; minimumVersion = 1.1.5;
}; };
}; };
7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/huri000/SwiftEntryKit";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.0.0;
};
};
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */ = { 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/onevcat/Kingfisher"; repositoryURL = "https://github.com/onevcat/Kingfisher";
@ -1380,6 +1444,11 @@
package = 7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */; package = 7AABDE1B2532F3EB0041AFC6 /* XCRemoteSwiftPackageReference "PKHUD" */;
productName = PKHUD; productName = PKHUD;
}; };
7AC355492969652F00889457 /* SwiftEntryKit */ = {
isa = XCSwiftPackageProductDependency;
package = 7AC355482969652F00889457 /* XCRemoteSwiftPackageReference "SwiftEntryKit" */;
productName = SwiftEntryKit;
};
7AF58D332402A91C00CE01A0 /* Kingfisher */ = { 7AF58D332402A91C00CE01A0 /* Kingfisher */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */; package = 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */;

View File

@ -89,6 +89,15 @@
"revision" : "6190d0cefff3013e77ed567e6b074f324e5c5bf5", "revision" : "6190d0cefff3013e77ed567e6b074f324e5c5bf5",
"version" : "6.3.1" "version" : "6.3.1"
} }
},
{
"identity" : "swiftentrykit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/huri000/SwiftEntryKit",
"state" : {
"revision" : "5ad36cccf0c4b9fea32f4e9b17a8e38f07563ef0",
"version" : "2.0.0"
}
} }
], ],
"version" : 2 "version" : 2

View File

@ -4,38 +4,18 @@
type = "1" type = "1"
version = "2.0"> version = "2.0">
<Breakpoints> <Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.SwiftErrorBreakpoint">
<BreakpointContent
uuid = "C14D0996-5708-44D2-A6BA-4A4B50B522EE"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
<BreakpointContent
uuid = "CF01B44D-372B-4C78-A197-7FDEC607CE0E"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
scope = "1"
stopOnStyle = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy <BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.SymbolicBreakpoint"> BreakpointExtensionID = "Xcode.Breakpoint.SymbolicBreakpoint">
<BreakpointContent <BreakpointContent
uuid = "B15A9E9C-A0CD-4FC9-8E24-DD93FB1B677F" uuid = "676638C8-1CC5-4C04-98B0-1C0D6CB28B76"
shouldBeEnabled = "No" shouldBeEnabled = "Yes"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
symbolName = "UITableViewAlertForLayoutOutsideViewHierarchy" symbolName = "UITableViewAlertForLayoutOutsideViewHierarchy"
moduleName = ""> moduleName = "">
<Locations> <Locations>
<Location <Location
uuid = "B15A9E9C-A0CD-4FC9-8E24-DD93FB1B677F - 620169ab4c7c265a" uuid = "676638C8-1CC5-4C04-98B0-1C0D6CB28B76 - 620169ab4c7c265a"
shouldBeEnabled = "Yes" shouldBeEnabled = "Yes"
ignoreCount = "0" ignoreCount = "0"
continueAfterRunningActions = "No" continueAfterRunningActions = "No"
@ -47,74 +27,5 @@
</Locations> </Locations>
</BreakpointContent> </BreakpointContent>
</BreakpointProxy> </BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "CFC2DD73-A257-45F3-A7A8-7D9462944F86"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoCat/Extensions/AudioEngine.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "12"
endingLineNumber = "12"
landmarkName = "setCategoryAsync(_:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.SwiftErrorBreakpoint">
<BreakpointContent
uuid = "4F72AC4F-FBCE-4C10-8BC2-2F434652DB31"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
<BreakpointContent
uuid = "42580582-DA14-40D4-869A-FF91FCA9957C"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
breakpointStackSelectionBehavior = "1"
scope = "1"
stopOnStyle = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "CA002588-A70B-4F96-BD13-7CC6C39BC2D5"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "../../../Library/Developer/Xcode/DerivedData/AutoCat-fhilwnlnsrpirleiajogdcyhyyey/SourcePackages/checkouts/RxSwift/RxCocoa/Foundation/URLSession+Rx.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "193"
endingLineNumber = "193"
landmarkName = "data(request:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "2B5BCCAE-FCA2-43D1-9835-08DB7E24B91C"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoCat/Utils/RxRealmDataSource.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "35"
endingLineNumber = "35"
landmarkName = "init(table:data:cellIdentifier:onSizeChanged:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints> </Breakpoints>
</Bucket> </Bucket>

View File

@ -0,0 +1,35 @@
import UIKit
extension UIControl {
func addAction(for controlEvent: UIControl.Event = .touchUpInside, _ closure: @escaping () -> Void) {
addActionImpl(for: controlEvent, closure: closure)
}
func addActionAsync(for controlEvent: UIControl.Event = .touchUpInside, _ closure: @escaping () async -> Void) {
addActionImpl(for: controlEvent) {
Task {
await closure()
}
}
}
func addActionImpl(for controlEvents: UIControl.Event, closure: @escaping () -> Void) {
if #available(iOS 14.0, *) {
addAction(UIAction { _ in closure() }, for: controlEvents)
} else {
@objc class ClosureSleeve: NSObject {
let closure:()->()
init(_ closure: @escaping()->()) { self.closure = closure }
@objc func invoke() { closure() }
}
let sleeve = ClosureSleeve(closure)
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
objc_setAssociatedObject(self, "\(UUID())", sleeve, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
}

View File

@ -0,0 +1,15 @@
import UIKit
extension UIEdgeInsets {
init(all: CGFloat) {
self.init(top: all, left: all, bottom: all, right: all)
}
}
extension UIEdgeInsets {
static func all(_ value: CGFloat) -> UIEdgeInsets {
.init(all: value)
}
}

View File

@ -0,0 +1,13 @@
import UIKit
extension UIView {
func pin(to view: UIView, insets: UIEdgeInsets = .zero) {
NSLayoutConstraint.activate([
leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: insets.left),
trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -insets.right),
topAnchor.constraint(equalTo: view.topAnchor, constant: insets.top),
bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -insets.bottom)
])
}
}

View File

@ -0,0 +1,80 @@
import UIKit
enum ACButtonStyle {
case generic
case roundedBlue
}
class ACButton: UIButton {
private var style: ACButtonStyle = .generic
convenience init(style: ACButtonStyle = .roundedBlue, title: String, onTap: @escaping () -> Void) {
self.init()
self.style(style)
self.onTap(onTap)
self.title(title)
translatesAutoresizingMaskIntoConstraints = false
}
convenience init(style: ACButtonStyle = .roundedBlue, title: String, onTapAsync: @escaping () async -> Void) {
self.init()
self.style(style)
self.onTapAsync(onTapAsync)
self.title(title)
translatesAutoresizingMaskIntoConstraints = false
}
override func layoutSubviews() {
super.layoutSubviews()
if style == .roundedBlue {
self.layer.opacity = self.isEnabled ? 1 : 0.5
} else {
self.layer.opacity = 1
}
}
@discardableResult
func style(_ style: ACButtonStyle) -> ACButton {
self.style = style
switch style {
case .generic:
break
case .roundedBlue:
backgroundColor = .systemBlue
layer.cornerRadius = 6
}
return self
}
@discardableResult
func title(_ title: String) -> ACButton {
setTitle(title, for: .normal)
return self
}
@discardableResult
func enable(_ enabled: Bool) -> ACButton {
isEnabled = enabled
return self
}
@discardableResult
func onTap(_ handler: @escaping () -> Void) -> ACButton {
addAction(for: .touchUpInside, handler)
return self
}
@discardableResult
func onTapAsync(_ handler: @escaping () async -> Void) -> ACButton {
addActionAsync(for: .touchUpInside, handler)
return self
}
}

View File

@ -173,17 +173,17 @@
<color key="backgroundColor" systemColor="systemBackgroundColor"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes> <prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="EventCell" id="QIb-Hv-tvk" customClass="EventCell" customModule="AutoCat" customModuleProvider="target"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="EventCell" id="QIb-Hv-tvk" customClass="EventCell" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="50" width="375" height="430.5"/> <rect key="frame" x="0.0" y="50" width="375" height="431.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QIb-Hv-tvk" id="Ypt-ch-fGT"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="QIb-Hv-tvk" id="Ypt-ch-fGT">
<rect key="frame" x="0.0" y="0.0" width="375" height="430.5"/> <rect key="frame" x="0.0" y="0.0" width="375" height="431.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HP8-oO-yhP"> <stackView opaque="NO" contentMode="scaleToFill" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="HP8-oO-yhP">
<rect key="frame" x="16" y="8" width="343" height="414.5"/> <rect key="frame" x="16" y="8" width="343" height="415.5"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="k4Z-KM-byE"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="k4Z-KM-byE">
<rect key="frame" x="0.0" y="0.0" width="335" height="414.5"/> <rect key="frame" x="0.0" y="0.0" width="335" height="415.5"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xcQ-Wz-gJ0"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xcQ-Wz-gJ0">
<rect key="frame" x="0.0" y="0.0" width="335" height="201"/> <rect key="frame" x="0.0" y="0.0" width="335" height="201"/>
@ -192,7 +192,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1tQ-zM-6T9"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1tQ-zM-6T9">
<rect key="frame" x="0.0" y="209" width="335" height="205.5"/> <rect key="frame" x="0.0" y="209" width="335" height="206.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/> <fontDescription key="fontDescription" style="UICTFontTextStyleSubhead"/>
<color key="textColor" systemColor="secondaryLabelColor"/> <color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
@ -200,7 +200,7 @@
</subviews> </subviews>
</stackView> </stackView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="750" verticalHuggingPriority="251" image="person" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="CFI-xa-eLs"> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="750" verticalHuggingPriority="251" image="person" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="CFI-xa-eLs">
<rect key="frame" x="343" y="1.5" width="0.0" height="412"/> <rect key="frame" x="343" y="1.5" width="0.0" height="413"/>
</imageView> </imageView>
</subviews> </subviews>
</stackView> </stackView>
@ -597,50 +597,19 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<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"/>
<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="SwiftMaskTextfield" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="250" height="50.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleTitle0"/>
<textInputTraits key="textInputTraits" returnKeyType="done"/>
<connections>
<action selector="textFieldDidBeginEditing:" destination="twc-qR-t1G" eventType="editingDidBegin" id="Kvu-xK-QuZ"/>
<action selector="textFieldDidChange:" destination="twc-qR-t1G" eventType="editingChanged" id="x69-Ym-Zdm"/>
</connections>
</textField>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" 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"/>
<color key="backgroundColor" systemColor="systemBlueColor"/>
<constraints>
<constraint firstAttribute="height" constant="48" id="YE0-lL-OwL"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<state key="normal" title="Check">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="checkTapped:" destination="twc-qR-t1G" eventType="touchUpInside" id="WiK-lL-7q7"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstAttribute="width" constant="250" id="lqO-Yy-NyQ"/>
</constraints>
</stackView>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="onDrag" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="JKr-UE-x8f"> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" keyboardDismissMode="onDrag" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="JKr-UE-x8f">
<rect key="frame" x="0.0" y="206.5" width="375" height="411.5"/> <rect key="frame" x="0.0" y="44" width="375" height="623"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/>
<prototypes> <prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="VehicleCell" id="3ON-lr-UlV" 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="3ON-lr-UlV" customClass="VehicleCell" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="50" width="375" height="84.5"/> <rect key="frame" x="0.0" y="50" width="375" height="94.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="3ON-lr-UlV" id="IGw-UK-ebp"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="3ON-lr-UlV" id="IGw-UK-ebp">
<rect key="frame" x="0.0" y="0.0" width="375" height="84.5"/> <rect key="frame" x="0.0" y="0.0" width="375" height="94.5"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="6IZ-gM-D28"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="6IZ-gM-D28">
<rect key="frame" x="8" y="8" width="359" height="68.5"/> <rect key="frame" x="8" y="8" width="359" height="78.5"/>
<subviews> <subviews>
<stackView opaque="NO" contentMode="scaleToFill" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="Rz6-wH-O1q"> <stackView opaque="NO" contentMode="scaleToFill" spacing="4" translatesAutoresizingMaskIntoConstraints="NO" id="Rz6-wH-O1q">
<rect key="frame" x="0.0" y="0.0" width="359" height="20"/> <rect key="frame" x="0.0" y="0.0" width="359" height="20"/>
@ -675,18 +644,15 @@
</subviews> </subviews>
</stackView> </stackView>
<stackView opaque="NO" contentMode="scaleToFill" alignment="bottom" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="nX1-KA-jqp"> <stackView opaque="NO" contentMode="scaleToFill" alignment="bottom" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="nX1-KA-jqp">
<rect key="frame" x="0.0" y="28" width="359" height="40.5"/> <rect key="frame" x="0.0" y="28" width="359" height="50.5"/>
<subviews> <subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="VHX-o0-3BP" customClass="PlateView" customModule="AutoCat" customModuleProvider="target"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="VHX-o0-3BP" customClass="PlateView" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.5" width="295" height="40"/> <rect key="frame" x="0.0" y="0.5" width="295" height="50"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/>
<color key="tintColor" systemColor="systemOrangeColor"/> <color key="tintColor" systemColor="systemOrangeColor"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="vzo-oF-mWb"/>
</constraints>
</view> </view>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="bottom" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="ApN-fV-Qw4"> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" alignment="bottom" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="ApN-fV-Qw4">
<rect key="frame" x="303" y="0.5" width="56" height="40"/> <rect key="frame" x="303" y="10.5" width="56" height="40"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="1.01.2021" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rKr-3e-WYb"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" text="1.01.2021" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rKr-3e-WYb">
<rect key="frame" x="0.0" y="0.0" width="56" height="16"/> <rect key="frame" x="0.0" y="0.0" width="56" height="16"/>
@ -731,11 +697,9 @@
<viewLayoutGuide key="safeArea" id="3Jk-FW-b3r"/> <viewLayoutGuide key="safeArea" id="3Jk-FW-b3r"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints> <constraints>
<constraint firstItem="JKr-UE-x8f" firstAttribute="top" secondItem="3Jk-FW-b3r" secondAttribute="top" id="PUg-nV-TN6"/>
<constraint firstItem="JKr-UE-x8f" firstAttribute="trailing" secondItem="3Jk-FW-b3r" secondAttribute="trailing" id="Tc5-ri-5RD"/> <constraint firstItem="JKr-UE-x8f" firstAttribute="trailing" secondItem="3Jk-FW-b3r" secondAttribute="trailing" id="Tc5-ri-5RD"/>
<constraint firstItem="Peq-Zq-kNT" firstAttribute="top" secondItem="3Jk-FW-b3r" secondAttribute="top" constant="24" id="Tft-8o-Cb1"/> <constraint firstItem="JKr-UE-x8f" firstAttribute="bottom" secondItem="g5m-iL-O7A" secondAttribute="bottom" id="Zwj-XD-UhD"/>
<constraint firstItem="JKr-UE-x8f" firstAttribute="bottom" secondItem="3Jk-FW-b3r" secondAttribute="bottom" id="Zwj-XD-UhD"/>
<constraint firstItem="Peq-Zq-kNT" firstAttribute="centerX" secondItem="g5m-iL-O7A" secondAttribute="centerX" id="fXl-Na-1gb"/>
<constraint firstItem="JKr-UE-x8f" firstAttribute="top" secondItem="Peq-Zq-kNT" secondAttribute="bottom" constant="24" id="mm9-rL-KQ1"/>
<constraint firstItem="JKr-UE-x8f" firstAttribute="leading" secondItem="3Jk-FW-b3r" secondAttribute="leading" id="vfN-fu-5pA"/> <constraint firstItem="JKr-UE-x8f" firstAttribute="leading" secondItem="3Jk-FW-b3r" secondAttribute="leading" id="vfN-fu-5pA"/>
</constraints> </constraints>
</view> </view>
@ -754,9 +718,7 @@
</rightBarButtonItems> </rightBarButtonItems>
</navigationItem> </navigationItem>
<connections> <connections>
<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="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"/>
@ -812,10 +774,10 @@
</objects> </objects>
<point key="canvasLocation" x="1704.8" y="-701.19940029985014"/> <point key="canvasLocation" x="1704.8" y="-701.19940029985014"/>
</scene> </scene>
<!--Tab Bar Controller--> <!--Main Tab Controller-->
<scene sceneID="YhQ-kn-py3"> <scene sceneID="YhQ-kn-py3">
<objects> <objects>
<tabBarController id="s9R-9a-TOT" sceneMemberID="viewController"> <tabBarController id="s9R-9a-TOT" customClass="MainTabController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="7gI-Jq-j4q"> <tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="7gI-Jq-j4q">
<rect key="frame" x="0.0" y="0.0" width="414" height="49"/> <rect key="frame" x="0.0" y="0.0" width="414" height="49"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
@ -824,6 +786,7 @@
<connections> <connections>
<segue destination="TSb-ZG-qfD" kind="relationship" relationship="viewControllers" id="Bwf-98-gjF"/> <segue destination="TSb-ZG-qfD" kind="relationship" relationship="viewControllers" id="Bwf-98-gjF"/>
<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="dxo-XS-x8Q" kind="relationship" relationship="viewControllers" id="MgV-gx-h7p"/>
<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"/>
</connections> </connections>
@ -951,6 +914,22 @@
</objects> </objects>
<point key="canvasLocation" x="199" y="143"/> <point key="canvasLocation" x="199" y="143"/>
</scene> </scene>
<!--Add-->
<scene sceneID="bCG-fh-cdJ">
<objects>
<viewController id="dxo-XS-x8Q" customClass="DummyNewController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="7Rw-QC-Av7">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="vIj-pz-YHR"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
<tabBarItem key="tabBarItem" title="Add" image="plus" catalog="system" id="X0w-PF-Dn8"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="C2T-ZN-q8G" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="929" y="-260"/>
</scene>
<!--Global Events Controller--> <!--Global Events Controller-->
<scene sceneID="akP-Pw-M4Q"> <scene sceneID="akP-Pw-M4Q">
<objects> <objects>
@ -989,11 +968,11 @@
</objects> </objects>
<point key="canvasLocation" x="7518" y="144"/> <point key="canvasLocation" x="7518" y="144"/>
</scene> </scene>
<!--Check--> <!--History-->
<scene sceneID="pUX-kf-oY1"> <scene sceneID="pUX-kf-oY1">
<objects> <objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="TSb-ZG-qfD" sceneMemberID="viewController"> <navigationController automaticallyAdjustsScrollViewInsets="NO" id="TSb-ZG-qfD" sceneMemberID="viewController">
<tabBarItem key="tabBarItem" title="Check" image="check" landscapeImage="check-compact" id="QJd-35-4OB"/> <tabBarItem key="tabBarItem" title="History" image="clock.arrow.circlepath" catalog="system" id="QJd-35-4OB"/>
<toolbarItems/> <toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="AAc-4d-GNh"> <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="AAc-4d-GNh">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/> <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
@ -1084,14 +1063,14 @@
</scene> </scene>
</scenes> </scenes>
<resources> <resources>
<image name="check" width="25" height="25"/> <image name="clock.arrow.circlepath" catalog="system" width="128" height="112"/>
<image name="check-compact" width="18" height="18"/>
<image name="doc.on.doc" catalog="system" width="116" height="128"/> <image name="doc.on.doc" catalog="system" width="116" height="128"/>
<image name="exclamationmark.arrow.triangle.2.circlepath" catalog="system" width="128" height="104"/> <image name="exclamationmark.arrow.triangle.2.circlepath" catalog="system" width="128" height="104"/>
<image name="line.horizontal.3.decrease" catalog="system" width="128" height="73"/> <image name="line.horizontal.3.decrease" catalog="system" width="128" height="73"/>
<image name="map" catalog="system" width="128" height="112"/> <image name="map" catalog="system" width="128" height="112"/>
<image name="person" catalog="system" width="128" height="121"/> <image name="person" catalog="system" width="128" height="121"/>
<image name="play.fill" catalog="system" width="117" height="128"/> <image name="play.fill" catalog="system" width="117" height="128"/>
<image name="plus" catalog="system" width="128" height="113"/>
<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"/>
<image name="search" width="23" height="23"/> <image name="search" width="23" height="23"/>

View File

@ -23,6 +23,8 @@ class VehicleCell: UITableViewCell, ConfigurableCell {
func configure(with vehicle: Vehicle) { func configure(with vehicle: Vehicle) {
self.name.text = vehicle.brand?.name?.original ?? "<unknown>" self.name.text = vehicle.brand?.name?.original ?? "<unknown>"
self.plate.number = PlateNumber(vehicle.getNumber()) self.plate.number = PlateNumber(vehicle.getNumber())
self.plate.fontSize = 40
if vehicle.unrecognized { if vehicle.unrecognized {
self.plate.foreground = .systemRed self.plate.foreground = .systemRed
} else if vehicle.outdated { } else if vehicle.outdated {

View File

@ -27,29 +27,30 @@ extension String.StringInterpolation {
} }
} }
class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegate, PNKeyboardDelegate { class CheckController: UIViewController, UITableViewDelegate, UISearchResultsUpdating {
@IBOutlet weak var number: SwiftMaskTextfield!
@IBOutlet weak var check: UIButton!
@IBOutlet weak var history: UITableView! @IBOutlet weak var history: UITableView!
private let bag = DisposeBag() private let bag = DisposeBag()
private var historyDataSource: RealmSectionedDataSource<Vehicle, VehicleCell>! private var historyDataSource: RealmSectionedDataSource<Vehicle, VehicleCell>!
private var historyFilter: HistoryFilter = .all private var historyFilter: HistoryFilter = .all
private let searchController = UISearchController(searchResultsController: nil)
// MARK: - Lifecycle // MARK: - Lifecycle
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = NSLocalizedString("Search plate numbers", comment: "")
searchController.hidesNavigationBarDuringPresentation = false
navigationItem.searchController = searchController
guard let realm = try? Realm() else { return } guard let realm = try? Realm() else { return }
self.hideKeyboardWhenTappedAround() self.hideKeyboardWhenTappedAround()
let keyboard = PNKeyboard(target: self.number)
keyboard.delegate = self
//self.number.formatPattern = "@###@@###"
self.number.inputView = keyboard
self.check.isEnabled = false
DispatchQueue.main.async { DispatchQueue.main.async {
self.historyDataSource = RealmSectionedDataSource(table: self.history, data: realm.objects(Vehicle.self).sorted(byKeyPath: "updatedDate", ascending: false)) { count in self.historyDataSource = RealmSectionedDataSource(table: self.history, data: realm.objects(Vehicle.self).sorted(byKeyPath: "updatedDate", ascending: false)) { count in
@ -61,11 +62,6 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat
NotificationCenter.default.addObserver(self, selector:#selector(self.calendarDayDidChange(_:)), name:NSNotification.Name.NSCalendarDayChanged, object:nil) NotificationCenter.default.addObserver(self, selector:#selector(self.calendarDayDidChange(_:)), name:NSNotification.Name.NSCalendarDayChanged, object:nil)
} }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//self.navigationController?.setNavigationBarHidden(true, animated: false)
}
override func viewWillDisappear(_ animated: Bool) { override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated) super.viewWillDisappear(animated)
if let index = self.history.indexPathForSelectedRow { if let index = self.history.indexPathForSelectedRow {
@ -86,7 +82,9 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat
switch ad.quickAction { switch ad.quickAction {
case .check: case .check:
ad.quickAction = .none ad.quickAction = .none
self.number.becomeFirstResponder() if let tabBar = tabBarController as? MainTabController {
tabBar.showCheckPuller()
}
break break
case .checkNumber(let number, let event): case .checkNumber(let number, let event):
ad.quickAction = .none ad.quickAction = .none
@ -204,13 +202,8 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat
// MARK: - Checking new number // MARK: - Checking new number
@IBAction func checkTapped(_ sender: UIButton) { func checkTapped(number: String) {
guard let number = self.number.text else { return }
let numberNormalized = number.filter { !$0.isWhitespace }.uppercased() let numberNormalized = number.filter { !$0.isWhitespace }.uppercased()
self.number.resignFirstResponder()
self.number.text = nil
self.check.isEnabled = false
var events: [VehicleEvent] = [] var events: [VehicleEvent] = []
do { do {
@ -258,29 +251,6 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat
} }
} }
// MARK: - UITextFieldDelegate
@IBAction func textFieldDidBeginEditing(_ textField: UITextField) {
RxLocationManager.requestCurrentLocation().subscribe().disposed(by: self.bag)
}
@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 {
self.checkTapped(self.check)
}
}
// MARK: - UITableViewDelegate // MARK: - UITableViewDelegate
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
@ -322,6 +292,23 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat
} }
} }
// MARK: - UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController) {
guard let realm = try? Realm() else {
return
}
var query = realm.objects(Vehicle.self)
.sorted(byKeyPath: "updatedDate", ascending: false)
if let text = searchController.searchBar.text?.uppercased(), !text.isEmpty {
query = query.filter("number CONTAINS '\(text)'")
}
historyDataSource.setQuery(query)
}
// MARK: - Contextual actions // MARK: - Contextual actions
func update(vehicle: Vehicle) { func update(vehicle: Vehicle) {

View File

@ -0,0 +1,6 @@
import UIKit
/// Dummy controller for detecting tap on "plus" tab
class DummyNewController: UIViewController {
}

View File

@ -0,0 +1,55 @@
import UIKit
import SwiftEntryKit
import AutoCatCore
import RxSwift
class MainTabController: UITabBarController, UITabBarControllerDelegate {
private let bag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = self
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if viewController is DummyNewController {
showCheckPuller()
return false
} else {
return true
}
}
func showCheckPuller() {
guard let checkNav = viewControllers?.first as? UINavigationController,
let checkController = checkNav.viewControllers.first as? CheckController
else {
return
}
var attributes = EKAttributes.bottomToast
attributes.displayDuration = .infinity
attributes.entryBackground = .color(color: .init(.secondarySystemBackground))
attributes.screenBackground = .color(color: EKColor(UIColor(white: 0, alpha: 0.7)))
attributes.roundCorners = .top(radius: 24)
attributes.screenInteraction = .dismiss
attributes.entryInteraction = .forward
attributes.entranceAnimation = .init(translate: .init(duration: 0.2))
attributes.exitAnimation = .init(translate: .init(duration: 0.2))
let newNumberController = NewNumberController()
newNumberController.onCheck = { number in
SwiftEntryKit.dismiss {
self.selectedIndex = 0
checkController.checkTapped(number: number)
}
}
SwiftEntryKit.display(entry: newNumberController, using: attributes)
// User probably just saw a vehicle and is about to start entering plate number
// Requesting current location ASAP while we still close to initial location
RxLocationManager.requestCurrentLocation().subscribe().disposed(by: self.bag)
}
}

View File

@ -0,0 +1,83 @@
import UIKit
import AutoCatCore
class NewNumberController: UIViewController {
public var onCheck: ((String) -> Void)?
private lazy var keyboardView: PNKeyboard = {
let keyboard = PNKeyboard(target: self.plateView)
keyboard.delegate = self
return keyboard
}()
private lazy var plateView: PlateView = {
let view = PlateView(frame: .zero)
view.fontSize = 48
view.number = PlateNumber("")
view.onChange = onNumberChanged
view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
view.accessibilityIdentifier = "plateView"
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"
return button
}()
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()
label.text = NSLocalizedString("Check number", comment: "")
label.font = UIFont.preferredFont(forTextStyle: .headline)
label.textAlignment = .center
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
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()
view.addSubview(mainStackView)
mainStackView.pin(to: view, insets: .init(top: 16, left: 16, bottom: 16, right: 16))
}
func check() {
guard let number = plateView.number, number.isValid else {
return
}
let numberNormalized = number.asString().filter { !$0.isWhitespace }.uppercased()
onCheck?(numberNormalized)
}
func onNumberChanged() {
checkButton.isEnabled = plateView.number?.isValid ?? false
}
}
extension NewNumberController: PNKeyboardDelegate {
func returnClicked() {
check()
}
}

View File

@ -15,12 +15,14 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
var vehicle: Vehicle? { var vehicle: Vehicle? {
didSet { didSet {
loadViewIfNeeded() //loadViewIfNeeded()
if isViewLoaded {
self.updateReport() self.updateReport()
self.form.allSections.forEach { $0.reload() } self.form.allSections.forEach { $0.reload() }
self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: false) self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: false)
} }
} }
}
private var notificationToken: NotificationToken? private var notificationToken: NotificationToken?
var number: String? { var number: String? {
@ -205,8 +207,8 @@ class ReportController: FormViewController, MediaBrowserViewControllerDataSource
return value ? yes : no return value ? yes : no
} }
override func viewWillAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewDidAppear(animated)
guard let ad = UIApplication.shared.delegate as? AppDelegate else { return } guard let ad = UIApplication.shared.delegate as? AppDelegate else { return }
self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: animated) self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: animated)

View File

@ -33,6 +33,7 @@ class SearchController: UIViewController, UISearchResultsUpdating, UITableViewDe
searchController.searchResultsUpdater = self searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false searchController.obscuresBackgroundDuringPresentation = false
searchController.searchBar.placeholder = NSLocalizedString("Search plate numbers", comment: "") searchController.searchBar.placeholder = NSLocalizedString("Search plate numbers", comment: "")
searchController.hidesNavigationBarDuringPresentation = false
navigationItem.searchController = searchController navigationItem.searchController = searchController
definesPresentationContext = true definesPresentationContext = true

View File

@ -18,16 +18,23 @@ class RealmSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource
private var cellIdentifier: String private var cellIdentifier: String
private var filterPredicate: FilterPredicate<Item>? private var filterPredicate: FilterPredicate<Item>?
private let onSizeChanged: ((Int) -> Void)?
init(table: UITableView, data: Results<Item>, cellIdentifier: String = String(describing: Cell.self), onSizeChanged: ((Int) -> Void)? = nil) { init(table: UITableView, data: Results<Item>, cellIdentifier: String = String(describing: Cell.self), onSizeChanged: ((Int) -> Void)? = nil) {
self.tv = table self.tv = table
self.data = data self.data = data
self.cellIdentifier = cellIdentifier self.cellIdentifier = cellIdentifier
self.onSizeChanged = onSizeChanged
super.init() super.init()
self.tv.dataSource = self self.tv.dataSource = self
self.tv.reloadData() self.tv.reloadData()
startObservingChanges()
}
func startObservingChanges() {
self.notificationToken = self.data.observe { changes in self.notificationToken = self.data.observe { changes in
onSizeChanged?(self.data.count) self.onSizeChanged?(self.data.count)
switch changes { switch changes {
case .initial: case .initial:
self.reload(animated: false) self.reload(animated: false)
@ -170,4 +177,9 @@ class RealmSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource
return result return result
} }
func setQuery(_ query: Results<Item>) {
self.data = query
startObservingChanges()
}
} }

View File

@ -66,11 +66,9 @@ class RxSectionedDataSource<Item,Cell>: NSObject, UITableViewDataSource where I
DispatchQueue.global().async { DispatchQueue.global().async {
let newSections = self.items.groupedByDate(type: self.sortParam) let newSections = self.items.groupedByDate(type: self.sortParam)
let changeset = StagedChangeset(source: self.sections, target: newSections)
DispatchQueue.main.async { DispatchQueue.main.async {
self.tv.reload(using: changeset, with: .automatic) { newSects in self.sections = newSections
self.sections = newSects self.tv.reloadData()
}
} }
} }
} }

View File

@ -110,8 +110,11 @@ class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
private weak var target: UIKeyInput? private weak var target: UIKeyInput?
weak var delegate: PNKeyboardDelegate? weak var delegate: PNKeyboardDelegate?
init(target: UIKeyInput) { private let insets: UIEdgeInsets
init(target: UIKeyInput, insets: UIEdgeInsets = .zero) {
self.target = target self.target = target
self.insets = insets
super.init(frame: .zero) super.init(frame: .zero)
self.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.autoresizingMask = [.flexibleWidth, .flexibleHeight]
@ -176,10 +179,10 @@ class PNKeyboard: UIView, UIInputViewAudioFeedback, PNButtonDelegate {
self.addSubview(mainStack) self.addSubview(mainStack)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
mainStack.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 16), mainStack.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: insets.left),
mainStack.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -16), mainStack.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -insets.right),
mainStack.topAnchor.constraint(equalTo: self.topAnchor, constant: 16), mainStack.topAnchor.constraint(equalTo: self.topAnchor, constant: insets.top),
mainStack.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: -16) mainStack.bottomAnchor.constraint(equalTo: self.safeAreaLayoutGuide.bottomAnchor, constant: -insets.bottom)
]) ])
} }

View File

@ -1,6 +1,15 @@
import UIKit import UIKit
import AutoCatCore import AutoCatCore
private class CALayerAnimationsDisablingDelegate: NSObject, CALayerDelegate {
static let shared = CALayerAnimationsDisablingDelegate()
private let null = NSNull()
func action(for layer: CALayer, forKey event: String) -> CAAction? {
null
}
}
class PlateView: UIView { class PlateView: UIView {
// Some driver plate parameters from "ГОСТ Р 50577-93" // Some driver plate parameters from "ГОСТ Р 50577-93"
// http://docs.cntd.ru/document/gost-r-50577-93 // http://docs.cntd.ru/document/gost-r-50577-93
@ -27,9 +36,25 @@ class PlateView: UIView {
} }
} }
var fontSize: CGFloat = 10 {
didSet {
self.layoutSubviews()
}
}
var onChange: (() -> Void)?
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
setup()
}
func setup() {
self.layer.backgroundColor = UIColor.clear.cgColor self.layer.backgroundColor = UIColor.clear.cgColor
self.bgLayer.cornerRadius = 6 //self.bounds.height/8 self.bgLayer.cornerRadius = 6 //self.bounds.height/8
@ -56,6 +81,20 @@ class PlateView: UIView {
self.flagLayer.contentsScale = UIScreen.main.scale self.flagLayer.contentsScale = UIScreen.main.scale
self.layer.addSublayer(self.flagLayer) self.layer.addSublayer(self.flagLayer)
disableAnimations(for: [
bgLayer,
mainBgLayer,
regionBgLayer,
numberLayer,
regionLayer,
countryLayer,
flagLayer
])
}
func disableAnimations(for layers: [CALayer]) {
layers.forEach { $0.delegate = CALayerAnimationsDisablingDelegate.shared }
} }
private func pathForFlag(in rect: CGRect) -> CGPath { private func pathForFlag(in rect: CGRect) -> CGPath {
@ -116,15 +155,31 @@ class PlateView: UIView {
} }
override var intrinsicContentSize: CGSize { override var intrinsicContentSize: CGSize {
guard self.bounds.width != 0 || self.bounds.height != 0 else {
return CGSize.zero let height = fontSize/1.1 + 4
let width = height/PlateView.aspectRatio
print("")
return CGSize(width: width, height: height)
}
} }
let curAspectRatio = self.bounds.height/self.bounds.width extension PlateView: UIKeyInput {
if curAspectRatio >= PlateView.aspectRatio {
return CGSize(width: self.bounds.width, height: self.bounds.width*PlateView.aspectRatio) var hasText: Bool {
} else { number?.hasText ?? false
return CGSize(width: self.bounds.height/PlateView.aspectRatio, height: self.bounds.height) }
func insertText(_ text: String) {
if number?.insertText(text) == true {
layoutSubviews()
onChange?()
}
}
func deleteBackward() {
if number?.deleteBackward() == true {
layoutSubviews()
onChange?()
} }
} }
} }

View File

@ -70,6 +70,9 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"Check date" = "Дата проверки"; "Check date" = "Дата проверки";
/* No comment provided by engineer. */
"Check number" = "Проверить номер";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"Check parameters" = "Параметры проверки"; "Check parameters" = "Параметры проверки";

View File

@ -1,9 +1,6 @@
/* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "7QQ-Qi-qEw"; */ /* Class = "UIBarButtonItem"; title = "Back"; ObjectID = "7QQ-Qi-qEw"; */
"7QQ-Qi-qEw.title" = "Назад"; "7QQ-Qi-qEw.title" = "Назад";
/* Class = "UITextField"; placeholder = "A001AA 777"; ObjectID = "8FU-Gy-4MU"; */
"8FU-Gy-4MU.placeholder" = "A001AA 777";
/* Class = "UILabel"; text = "00:00"; ObjectID = "bFQ-eU-5YJ"; */ /* Class = "UILabel"; text = "00:00"; ObjectID = "bFQ-eU-5YJ"; */
"bFQ-eU-5YJ.text" = "00:00"; "bFQ-eU-5YJ.text" = "00:00";
@ -31,8 +28,8 @@
/* Class = "UITabBarItem"; title = "Records"; ObjectID = "lxF-EY-z8V"; */ /* Class = "UITabBarItem"; title = "Records"; ObjectID = "lxF-EY-z8V"; */
"lxF-EY-z8V.title" = "Аудио"; "lxF-EY-z8V.title" = "Аудио";
/* Class = "UITabBarItem"; title = "Check"; ObjectID = "QJd-35-4OB"; */ /* Class = "UITabBarItem"; title = "History"; ObjectID = "QJd-35-4OB"; */
"QJd-35-4OB.title" = "Проверка"; "QJd-35-4OB.title" = "История";
/* Class = "UILabel"; text = "or"; ObjectID = "SXb-1Q-TxY"; */ /* Class = "UILabel"; text = "or"; ObjectID = "SXb-1Q-TxY"; */
"SXb-1Q-TxY.text" = "или"; "SXb-1Q-TxY.text" = "или";
@ -43,8 +40,8 @@
/* Class = "UITextField"; placeholder = "Email"; ObjectID = "Uey-88-eZL"; */ /* Class = "UITextField"; placeholder = "Email"; ObjectID = "Uey-88-eZL"; */
"Uey-88-eZL.placeholder" = "Email"; "Uey-88-eZL.placeholder" = "Email";
/* Class = "UIButton"; normalTitle = "Check"; ObjectID = "Ync-fd-xQI"; */ /* Class = "UITabBarItem"; title = "Add"; ObjectID = "X0w-PF-Dn8"; */
"Ync-fd-xQI.normalTitle" = "Проверить"; "X0w-PF-Dn8.title" = "Добавить";
/* Class = "UITabBarItem"; title = "Settings"; ObjectID = "zEL-ph-E2f"; */ /* Class = "UITabBarItem"; title = "Settings"; ObjectID = "zEL-ph-E2f"; */
"zEL-ph-E2f.title" = "Настройки"; "zEL-ph-E2f.title" = "Настройки";

View File

@ -5,12 +5,16 @@ import DifferenceKit
public struct DateSection<T>: Differentiable, DifferentiableSection, Hashable where T: Differentiable & Hashable { public struct DateSection<T>: Differentiable, DifferentiableSection, Hashable where T: Differentiable & Hashable {
var timestamp: Double = 0 var timestamp: Double = 0
public var header: String var dateString: String
public var elements: [T] public var elements: [T]
public var header: String {
"\(dateString) (\(elements.count))"
}
public init<C>(source: DateSection<T>, elements: C) where C : Swift.Collection, C.Element == Self.Collection.Element { public init<C>(source: DateSection<T>, elements: C) where C : Swift.Collection, C.Element == Self.Collection.Element {
self.timestamp = source.timestamp self.timestamp = source.timestamp
self.header = source.header self.dateString = source.dateString
self.elements = Array(elements) self.elements = Array(elements)
} }
@ -31,20 +35,20 @@ public struct DateSection<T>: Differentiable, DifferentiableSection, Hashable wh
let date = Date(timeIntervalSince1970: timestamp) let date = Date(timeIntervalSince1970: timestamp)
let dateInRegion = DateInRegion(date, region: Region.current) let dateInRegion = DateInRegion(date, region: Region.current)
if dateInRegion.isToday { if dateInRegion.isToday {
self.header = NSLocalizedString("Today", comment: "") self.dateString = NSLocalizedString("Today", comment: "")
} }
else if dateInRegion.isYesterday { else if dateInRegion.isYesterday {
self.header = NSLocalizedString("Yesterday", comment: "") self.dateString = NSLocalizedString("Yesterday", comment: "")
} else if dateInRegion.isAfterDate(weekStart, granularity: .day) { } else if dateInRegion.isAfterDate(weekStart, granularity: .day) {
formatter.dateFormat = "EEEE" formatter.dateFormat = "EEEE"
self.header = formatter.string(from: date) self.dateString = formatter.string(from: date)
} else if dateInRegion.isAfterDate(monthStart, orEqual: false, granularity: .day) { } else if dateInRegion.isAfterDate(monthStart, orEqual: false, granularity: .day) {
formatter.dateStyle = .medium formatter.dateStyle = .medium
formatter.timeStyle = .none formatter.timeStyle = .none
self.header = formatter.string(from: date) self.dateString = formatter.string(from: date)
} else { } else {
formatter.dateFormat = "LLLL yyyy" formatter.dateFormat = "LLLL yyyy"
self.header = formatter.string(from: date) self.dateString = formatter.string(from: date)
} }
self.timestamp = timestamp self.timestamp = timestamp
@ -74,7 +78,7 @@ public struct DateSection<T>: Differentiable, DifferentiableSection, Hashable wh
// MARK: - Differentiable // MARK: - Differentiable
public var differenceIdentifier: String { public var differenceIdentifier: String {
return header return dateString
} }
public func isContentEqual(to source: DateSection<T>) -> Bool { public func isContentEqual(to source: DateSection<T>) -> Bool {

View File

@ -1,12 +1,15 @@
import Foundation import Foundation
public class PlateNumber { public class PlateNumber {
private var number: String private var number: String = ""
private var numberEnglish: String private var numberEnglish: String = ""
private let maxLength = 9
private let mainPartLength = 6
private let isDigitMask = [false, true, true, true, false, false, true, true, true]
public init(_ string: String) { public init(_ string: String) {
self.number = string setNumber(string)
self.numberEnglish = String(self.number.map { Constants.pnLettersMap[$0] ?? $0 })
} }
public func asString() -> String { public func asString() -> String {
@ -14,12 +17,56 @@ public class PlateNumber {
} }
public func mainPart() -> String { public func mainPart() -> String {
let index = self.numberEnglish.index(self.numberEnglish.startIndex, offsetBy: 6) return String(self.numberEnglish.prefix(mainPartLength))
return String(self.numberEnglish[..<index])
} }
public func region() -> String { public func region() -> String {
let index = self.numberEnglish.index(self.numberEnglish.startIndex, offsetBy: 6) guard numberEnglish.count > mainPartLength else {
return String(self.numberEnglish[index...]) return ""
}
return String(self.numberEnglish.dropFirst(mainPartLength))
}
public var isValid: Bool {
number.count >= 8
}
public func setNumber(_ number: String) {
self.number = number
self.numberEnglish = String(self.number.map { Constants.pnLettersMap[$0] ?? $0 })
}
// MARK: - UIKeyInput
public var hasText: Bool {
return !number.isEmpty
}
// Returns true if number was changed
public func insertText(_ text: String) -> Bool {
guard number.count < maxLength, text.count == 1 else {
return false
}
// TODO: Do proper validation
// if text.first?.isNumber == isDigitMask[number.count] {
// setNumber(number + text)
// return true
// } else {
// return false
// }
setNumber(number + text)
return true
}
public func deleteBackward() -> Bool {
guard !number.isEmpty else {
return false
}
setNumber(String(number.dropLast()))
return true
} }
} }

View File

@ -364,7 +364,7 @@ public class Vehicle: Object, Decodable, Identifiable, Differentiable, Cloneable
// MARK: - Exportable // MARK: - Exportable
public static var csvHeader: String { public static var csvHeader: String {
return "Model, Color, Year, Plate Number, VIN, STS, PTS, Added Date, Updated date, Locations" return "Plate Number, Model, Color, Year, Owners, VIN, STS, PTS, Added Date, Updated date, Locations, Notes"
} }
public var csvLine: String { public var csvLine: String {
@ -379,16 +379,22 @@ public class Vehicle: Object, Decodable, Identifiable, Differentiable, Cloneable
eventsString.append(location + "; " + date + "\r\n") eventsString.append(location + "; " + date + "\r\n")
} }
return String(format: "\"%@\", %@, %d, %@, %@, %@, %@, \"%@\", \"%@\", \"%@\"", let notesString = self.notes.reduce("") { partialResult, note in
partialResult + note.text + "\r\n"
}
return String(format: "%@, \"%@\", %@, %d, %d, %@, %@, %@, \"%@\", \"%@\", \"%@\", \"%@\"",
self.number,
model, model,
self.color ?? "", self.color ?? "",
self.year, self.year,
self.number, self.ownershipPeriods.count,
self.vin1 ?? "", self.vin1 ?? "",
self.sts ?? "", self.sts ?? "",
self.pts ?? "", self.pts ?? "",
added, added,
updated, updated,
eventsString) eventsString,
notesString)
} }
} }