Settings update

This commit is contained in:
Selim Mustafaev 2020-05-13 14:39:19 +03:00
parent 9f676b9d3b
commit 7905d0ff25
11 changed files with 582 additions and 28 deletions

View File

@ -48,6 +48,7 @@
7A64AE812469E16100ABE48E /* ProgressAnimatedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE7B2469E16100ABE48E /* ProgressAnimatedView.swift */; };
7A64AE822469E16100ABE48E /* IHProgressHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE7C2469E16100ABE48E /* IHProgressHUD.swift */; };
7A64AE832469E16100ABE48E /* IHProgressHUD.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 7A64AE7D2469E16100ABE48E /* IHProgressHUD.bundle */; };
7A64AE85246AD12E00ABE48E /* GoogleAuth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A64AE84246AD12E00ABE48E /* GoogleAuth.swift */; };
7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD902242BF4A5009DE740 /* PlateView.swift */; };
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD90724329144009DE740 /* CenterTextLayer.swift */; };
7A6DD90A24329541009DE740 /* RoadNumbers2.0.otf in Resources */ = {isa = PBXBuildFile; fileRef = 7A6DD90924329541009DE740 /* RoadNumbers2.0.otf */; };
@ -56,6 +57,11 @@
7A7547DD2403180A004E8406 /* SectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DB2403180A004E8406 /* SectionHeader.swift */; };
7A7547DE2403180A004E8406 /* SectionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7A7547DC2403180A004E8406 /* SectionHeader.xib */; };
7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */; };
7A96AE2A246AFD6200297C33 /* Eureka in Frameworks */ = {isa = PBXBuildFile; productRef = 7A96AE29246AFD6200297C33 /* Eureka */; };
7A96AE2D246B2B7400297C33 /* GoogleSignInController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */; };
7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A96AE2E246B2BCD00297C33 /* WebKit.framework */; };
7A96AE31246B2FE400297C33 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE30246B2FE400297C33 /* Constants.swift */; };
7A96AE33246C095700297C33 /* Base64FS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A96AE32246C095700297C33 /* Base64FS.swift */; };
7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8B2435C38700258F61 /* CustomTextField.swift */; };
7AB67E8E2435D1A000258F61 /* CustomButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB67E8D2435D1A000258F61 /* CustomButton.swift */; };
7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFE727240455E200910EB7 /* SettingsController.swift */; };
@ -99,6 +105,7 @@
7A64AE7B2469E16100ABE48E /* ProgressAnimatedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressAnimatedView.swift; sourceTree = "<group>"; };
7A64AE7C2469E16100ABE48E /* IHProgressHUD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IHProgressHUD.swift; sourceTree = "<group>"; };
7A64AE7D2469E16100ABE48E /* IHProgressHUD.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = IHProgressHUD.bundle; sourceTree = "<group>"; };
7A64AE84246AD12E00ABE48E /* GoogleAuth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleAuth.swift; sourceTree = "<group>"; };
7A6DD902242BF4A5009DE740 /* PlateView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlateView.swift; sourceTree = "<group>"; };
7A6DD90724329144009DE740 /* CenterTextLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CenterTextLayer.swift; sourceTree = "<group>"; };
7A6DD90924329541009DE740 /* RoadNumbers2.0.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = RoadNumbers2.0.otf; sourceTree = "<group>"; };
@ -108,6 +115,10 @@
7A7547DC2403180A004E8406 /* SectionHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SectionHeader.xib; sourceTree = "<group>"; };
7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehiclePhotoCell.swift; sourceTree = "<group>"; };
7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ATGMediaBrowser.framework; path = Carthage/Build/iOS/ATGMediaBrowser.framework; sourceTree = "<group>"; };
7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GoogleSignInController.swift; sourceTree = "<group>"; };
7A96AE2E246B2BCD00297C33 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
7A96AE30246B2FE400297C33 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
7A96AE32246C095700297C33 /* Base64FS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Base64FS.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>"; };
7AEFE727240455E200910EB7 /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = "<group>"; };
@ -122,9 +133,11 @@
files = (
7AF58D342402A91C00CE01A0 /* Kingfisher in Frameworks */,
7A0516162414EC1200FC55AC /* Differentiator in Frameworks */,
7A96AE2F246B2BCD00297C33 /* WebKit.framework in Frameworks */,
7A11472823FEA1F400B424AF /* RealmSwift in Frameworks */,
7A11472123FEA18700B424AF /* RxCocoa in Frameworks */,
7A0516182414EC1200FC55AC /* RxDataSources in Frameworks */,
7A96AE2A246AFD6200297C33 /* Eureka in Frameworks */,
7A051611241412CA00FC55AC /* SwiftDate in Frameworks */,
7A11472323FEA18700B424AF /* RxBlocking in Frameworks */,
7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */,
@ -188,6 +201,7 @@
7A530B7924001D3300CBFE6E /* CheckController.swift */,
7AEFE727240455E200910EB7 /* SettingsController.swift */,
7A3F07AC2436350B00E59687 /* SearchController.swift */,
7A96AE2C246B2B7400297C33 /* GoogleSignInController.swift */,
);
path = Controllers;
sourceTree = "<group>";
@ -198,6 +212,7 @@
7A64AE772469E16100ABE48E /* IHProgressHUD */,
7A64AE6E2469DFB600ABE48E /* ATGMediaBrowser */,
7A6DD90724329144009DE740 /* CenterTextLayer.swift */,
7A96AE32246C095700297C33 /* Base64FS.swift */,
);
path = ThirdParty;
sourceTree = "<group>";
@ -206,6 +221,8 @@
isa = PBXGroup;
children = (
7A11474323FF06CA00B424AF /* Api.swift */,
7A64AE84246AD12E00ABE48E /* GoogleAuth.swift */,
7A96AE30246B2FE400297C33 /* Constants.swift */,
);
path = Utils;
sourceTree = "<group>";
@ -227,6 +244,7 @@
7A11474C23FFEE8700B424AF /* Frameworks */ = {
isa = PBXGroup;
children = (
7A96AE2E246B2BCD00297C33 /* WebKit.framework */,
7A92D0AB240425B100EF3B77 /* ATGMediaBrowser.framework */,
7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */,
);
@ -328,6 +346,7 @@
7A051610241412CA00FC55AC /* SwiftDate */,
7A0516152414EC1200FC55AC /* Differentiator */,
7A0516172414EC1200FC55AC /* RxDataSources */,
7A96AE29246AFD6200297C33 /* Eureka */,
);
productName = AutoCat;
productReference = 7A1146FD23FDE7E500B424AF /* AutoCat.app */;
@ -367,6 +386,7 @@
7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */,
7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */,
7A0516142414EC1200FC55AC /* XCRemoteSwiftPackageReference "RxDataSources" */,
7A96AE28246AFD6200297C33 /* XCRemoteSwiftPackageReference "Eureka" */,
);
productRefGroup = 7A1146FE23FDE7E500B424AF /* Products */;
projectDirPath = "";
@ -399,7 +419,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7A96AE33246C095700297C33 /* Base64FS.swift in Sources */,
7A530B802401803A00CBFE6E /* Vehicle.swift in Sources */,
7A96AE31246B2FE400297C33 /* Constants.swift in Sources */,
7A64AE822469E16100ABE48E /* IHProgressHUD.swift in Sources */,
7A11470123FDE7E500B424AF /* AppDelegate.swift in Sources */,
7A6DD90824329144009DE740 /* CenterTextLayer.swift in Sources */,
@ -413,12 +435,14 @@
7A64AE762469DFB600ABE48E /* ContentTransformers.swift in Sources */,
7A11471823FDEBFA00B424AF /* ReportController.swift in Sources */,
7A64AE7E2469E16100ABE48E /* RadialGradientLayer.swift in Sources */,
7A64AE85246AD12E00ABE48E /* GoogleAuth.swift in Sources */,
7A64AE7F2469E16100ABE48E /* IndefiniteAnimatedView.swift in Sources */,
7A11471A23FE839000B424AF /* AuthController.swift in Sources */,
7A530B7A24001D3300CBFE6E /* CheckController.swift in Sources */,
7A64AE742469DFB600ABE48E /* MediaContentView.swift in Sources */,
7A7547DD2403180A004E8406 /* SectionHeader.swift in Sources */,
7AF58D58240309CA00CE01A0 /* VehicleTextParamCell.swift in Sources */,
7A96AE2D246B2B7400297C33 /* GoogleSignInController.swift in Sources */,
7A11474723FF2AA500B424AF /* User.swift in Sources */,
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */,
7AF58D3124029E1000CE01A0 /* VehicleHeaderCell.swift in Sources */,
@ -697,6 +721,14 @@
minimumVersion = 2.0.0;
};
};
7A96AE28246AFD6200297C33 /* XCRemoteSwiftPackageReference "Eureka" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/xmartlabs/Eureka";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 5.2.1;
};
};
7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/airbnb/MagazineLayout";
@ -776,6 +808,11 @@
package = 7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */;
productName = RxRealm;
};
7A96AE29246AFD6200297C33 /* Eureka */ = {
isa = XCSwiftPackageProductDependency;
package = 7A96AE28246AFD6200297C33 /* XCRemoteSwiftPackageReference "Eureka" */;
productName = Eureka;
};
7AF58D2E24029C5200CE01A0 /* MagazineLayout */ = {
isa = XCSwiftPackageProductDependency;
package = 7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */;

View File

@ -10,6 +10,15 @@
"version": "4.1.0"
}
},
{
"package": "Eureka",
"repositoryURL": "https://github.com/xmartlabs/Eureka",
"state": {
"branch": null,
"revision": "9a30ae436ec9e9fcb8b3eb1bdfd95e95989d6ca5",
"version": "5.2.1"
}
},
{
"package": "InputMask",
"repositoryURL": "https://github.com/RedMadRobot/input-mask-ios",

View File

@ -24,5 +24,69 @@
stopOnStyle = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "2445735D-04AB-4C39-A7D2-AED33C44BBB5"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoCat/Controllers/GoogleSignInController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "86"
endingLineNumber = "86"
landmarkName = "getToken(code:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "A5665C58-1F74-4052-A342-38ACB119101F"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoCat/Controllers/GoogleSignInController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "94"
endingLineNumber = "94"
landmarkName = "getToken(code:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "20DDDF73-CE71-4674-9A6D-8D288D551536"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoCat/Controllers/GoogleSignInController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "90"
endingLineNumber = "90"
landmarkName = "getToken(code:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "68C7E1F5-1364-46D7-BE9D-09793D4882B9"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "AutoCat/Controllers/GoogleSignInController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "81"
endingLineNumber = "81"
landmarkName = "getToken(code:completion:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -19,7 +19,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let config = Realm.Configuration(
schemaVersion: 2,
schemaVersion: 3,
migrationBlock: { migration, oldSchemaVersion in
})

View File

@ -193,14 +193,14 @@
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" selectionStyle="blue" hidesAccessoryWhenEditing="NO" indentationLevel="1" indentationWidth="0.0" reuseIdentifier="VehicleCell" id="VEP-QD-i6y" customClass="VehicleCell" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="0.0" y="28" width="375" height="85"/>
<rect key="frame" x="0.0" y="28" width="375" height="85.5"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" tableViewCell="VEP-QD-i6y" id="8hH-8I-XLB">
<rect key="frame" x="0.0" y="0.0" width="375" height="85"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="85.5"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Kia (JF) Optima" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="AQY-7N-q8D">
<rect key="frame" x="8" y="8" width="124" height="21"/>
<rect key="frame" x="8" y="8" width="124" height="21.5"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
@ -212,7 +212,7 @@
<nil key="highlightedColor"/>
</label>
<view contentMode="scaleToFill" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cvf-vM-QnT" customClass="PlateView" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="8" y="37" width="317" height="40"/>
<rect key="frame" x="8" y="37.5" width="317" height="40"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Xoz-Iw-PCU"/>
@ -266,27 +266,7 @@
<view key="view" contentMode="scaleToFill" id="NFd-we-MVH">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8Te-C0-b8T" customClass="CustomButton" customModule="AutoCat" customModuleProvider="target">
<rect key="frame" x="16" y="20" width="343" height="40"/>
<color key="backgroundColor" systemColor="systemBlueColor" red="0.0" green="0.47843137250000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="40" id="Vtn-tL-qcQ"/>
</constraints>
<state key="normal" title="Logout">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="logout:" destination="4jU-Z3-PF2" eventType="touchUpInside" id="RSM-Bp-2sN"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="Uix-8K-fxh" firstAttribute="trailing" secondItem="8Te-C0-b8T" secondAttribute="trailing" constant="16" id="DsI-gO-q9W"/>
<constraint firstItem="8Te-C0-b8T" firstAttribute="top" secondItem="Uix-8K-fxh" secondAttribute="top" constant="20" id="J43-Oo-kme"/>
<constraint firstItem="8Te-C0-b8T" firstAttribute="leading" secondItem="Uix-8K-fxh" secondAttribute="leading" constant="16" id="iSk-SC-T1w"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Uix-8K-fxh"/>
</view>
<tabBarItem key="tabBarItem" title="Settings" image="gear" catalog="system" id="zEL-ph-E2f"/>
@ -405,6 +385,55 @@
</objects>
<point key="canvasLocation" x="4200.8000000000002" y="-585.1574212893554"/>
</scene>
<!--Google Sign In Controller-->
<scene sceneID="ztj-pr-ty7">
<objects>
<viewController storyboardIdentifier="GoogleSignInController" id="Ptg-6q-3w6" customClass="GoogleSignInController" customModule="AutoCat" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="NtL-RA-Nxs">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<wkWebView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="0QS-UT-hbi">
<rect key="frame" x="0.0" y="44" width="375" height="623"/>
<color key="backgroundColor" red="0.36078431370000003" green="0.38823529410000002" blue="0.4039215686" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<wkWebViewConfiguration key="configuration">
<audiovisualMediaTypes key="mediaTypesRequiringUserActionForPlayback" none="YES"/>
<wkPreferences key="preferences"/>
</wkWebViewConfiguration>
</wkWebView>
<navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="AMg-mc-MMG">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<items>
<navigationItem id="fZb-kM-9an">
<barButtonItem key="rightBarButtonItem" title="Close" id="ZHH-OZ-vHc">
<connections>
<action selector="close:" destination="Ptg-6q-3w6" id="VVY-eV-Yeg"/>
</connections>
</barButtonItem>
</navigationItem>
</items>
</navigationBar>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="0QS-UT-hbi" firstAttribute="top" secondItem="AMg-mc-MMG" secondAttribute="bottom" id="1l8-UT-leW"/>
<constraint firstItem="AMg-mc-MMG" firstAttribute="top" secondItem="4cf-6q-b5U" secondAttribute="top" id="50U-IM-aiw"/>
<constraint firstItem="AMg-mc-MMG" firstAttribute="leading" secondItem="4cf-6q-b5U" secondAttribute="leading" id="9Si-sE-9y6"/>
<constraint firstItem="AMg-mc-MMG" firstAttribute="trailing" secondItem="4cf-6q-b5U" secondAttribute="trailing" id="DuZ-iN-C4K"/>
<constraint firstItem="0QS-UT-hbi" firstAttribute="leading" secondItem="4cf-6q-b5U" secondAttribute="leading" id="RKF-L4-hnY"/>
<constraint firstItem="0QS-UT-hbi" firstAttribute="trailing" secondItem="4cf-6q-b5U" secondAttribute="trailing" id="gBv-r4-tWa"/>
<constraint firstItem="0QS-UT-hbi" firstAttribute="bottom" secondItem="4cf-6q-b5U" secondAttribute="bottom" id="sYj-Jg-IMn"/>
</constraints>
<viewLayoutGuide key="safeArea" id="4cf-6q-b5U"/>
</view>
<connections>
<outlet property="webView" destination="0QS-UT-hbi" id="vZb-CE-W3J"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="WxN-oK-U9s" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1704.8" y="-701.19940029985014"/>
</scene>
<!--Tab Bar Controller-->
<scene sceneID="YhQ-kn-py3">
<objects>

View File

@ -0,0 +1,98 @@
import UIKit
import WebKit
import CommonCrypto
class GoogleSignInController: UIViewController, WKNavigationDelegate {
@IBOutlet weak var webView: WKWebView!
private var codeVerifier: String = ""
override func viewDidLoad() {
super.viewDidLoad()
self.webView.navigationDelegate = self
#if targetEnvironment(macCatalyst)
self.webView.customUserAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15"
#else
self.webView.customUserAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_4_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Mobile/15E148 Safari/604.1"
#endif
self.codeVerifier = UUID().uuidString
let codeChallenge = self.sha256(string: self.codeVerifier) ?? ""
print("++++++++++++++++++")
print(codeVerifier)
print(codeChallenge)
let authUrlString = Constants.googleAuthURL
+ "?response_type=code"
+ "&code_challenge_method=S256"
+ "&scope=email%20profile"
+ "&redirect_uri=" + Constants.googleRedirectURL
+ "&client_id=" + Constants.googleClientId
+ "&code_challenge=" + codeChallenge
if let url = URL(string: authUrlString) {
let request = URLRequest(url: url)
self.webView.load(request)
}
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let url = navigationAction.request.url {
if let components = URLComponents(url: url, resolvingAgainstBaseURL: false) {
if let queryItems = components.queryItems {
if let code = queryItems.first(where: { $0.name == "code" })?.value {
decisionHandler(.cancel)
self.getToken(code: code) { error, idToken in
print("ID Token: \(idToken)")
}
return
}
}
}
}
decisionHandler(.allow)
}
@IBAction func close(_ sender: UIBarButtonItem) {
self.dismiss(animated: true, completion: nil)
}
func sha256(string: String) -> String? {
guard let data = string.data(using: .utf8) else { return nil }
var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
data.withUnsafeBytes {
_ = CC_SHA256($0.baseAddress, CC_LONG(data.count), &hash)
}
return String(data: Data(Base64FS.encode(data: hash)), encoding: .utf8)?.trimmingCharacters(in: CharacterSet(charactersIn: "="))
}
func getToken(code: String, completion: @escaping (Error?, String?) -> Void) {
let tokenUrlString = Constants.googleTokenURL
+ "?grant_type=authorization_code"
+ "&code=" + code
+ "&redirect_uri=" + Constants.googleRedirectURL
+ "&client_id=" + Constants.googleClientId
+ "&code_verifier=" + self.codeVerifier
if let url = URL(string: tokenUrlString) {
var request = URLRequest(url: url)
request.httpMethod = "POST"
URLSession.shared.dataTask(with: request) { data, response, error in
if let data = data {
if let str = String(data: data, encoding: .utf8) {
print(str)
}
} else {
completion(error, nil)
}
}
} else {
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey: "Bad URL"])
completion(error, nil)
}
}
}

View File

@ -1,16 +1,57 @@
import UIKit
import Eureka
class SettingsController: UIViewController {
class SettingsController: FormViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
form +++ Section("Profile")
<<< LabelRow("AutoCatAccount") { row in
row.title = "AutoCat Account"
row.value = Settings.shared.user.login
}
<<< LabelRow("GoogleAccount") { row in
row.title = "Google Account"
row.value = "Log In"
row.cellUpdate { cell, _ in
cell.accessoryType = .disclosureIndicator
}
}.onCellSelection { cell, row in
if Settings.shared.user.googleIdToken != nil {
self.displayLogoutSheet()
} else {
self.loginToGoogle()
}
}
+++ Section()
<<< ButtonRow("SignOut") { $0.title = "Sign Out" }.onCellSelection { cell, row in
self.logout()
}
}
@IBAction func logout(_ sender: UIButton) {
func logout() {
Settings.shared.user.token = ""
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.view.window?.rootViewController = storyboard.instantiateViewController(identifier: "AuthController")
}
func displayLogoutSheet() {
let sheet = UIAlertController(title: "Google Account", message: "You are currently signed in with email example@gmail.com. It allows us to find more data about vehicles.", preferredStyle: .actionSheet)
let cancel = UIAlertAction(title: "Cancel", style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) }
let logout = UIAlertAction(title: "Sign Out", style: .destructive) { _ in
Settings.shared.user.googleIdToken = nil
}
sheet.addAction(logout)
sheet.addAction(cancel)
self.present(sheet, animated: true, completion: nil)
}
func loginToGoogle() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(identifier: "GoogleSignInController")
self.present(vc, animated: true)
}
}

View File

@ -3,9 +3,11 @@ import Foundation
struct User: Codable {
let login: String
var token: String
var googleIdToken: String?
init() {
self.login = ""
self.token = ""
self.googleIdToken = ""
}
}

262
AutoCat/ThirdParty/Base64FS.swift vendored Normal file
View File

@ -0,0 +1,262 @@
//
// Base64FS.swift
//
// Created by Jack Chorley on 27/06/2017.
//
import Foundation
public class Base64FS {
private static let padding: UInt8 = 61 // Padding = "="
private static let filenameSafeAlphabet: [UInt8] = [
65, // 0 = "A"
66, // 1 = "B"
67, // 2 = "C"
68, // 3 = "D"
69, // 4 = "E"
70, // 5 = "F"
71, // 6 = "G"
72, // 7 = "H"
73, // 8 = "I"
74, // 9 = "J"
75, // 10 = "K"
76, // 11 = "L"
77, // 12 = "M"
78, // 13 = "N"
79, // 14 = "O"
80, // 15 = "P"
81, // 16 = "Q"
82, // 17 = "R"
83, // 18 = "S"
84, // 19 = "T"
85, // 20 = "U"
86, // 21 = "V"
87, // 22 = "W"
88, // 23 = "X"
89, // 24 = "Y"
90, // 25 = "Z"
97, // 26 = "a"
98, // 27 = "b"
99, // 28 = "c"
100, // 29 = "d"
101, // 30 = "e"
102, // 31 = "f"
103, // 32 = "g"
104, // 33 = "h"
105, // 34 = "i"
106, // 35 = "j"
107, // 36 = "k"
108, // 37 = "l"
109, // 38 = "m"
110, // 39 = "n"
111, // 40 = "o"
112, // 41 = "p"
113, // 42 = "q"
114, // 43 = "r"
115, // 44 = "s"
116, // 45 = "t"
117, // 46 = "u"
118, // 47 = "v"
119, // 48 = "w"
120, // 49 = "x"
121, // 50 = "y"
122, // 51 = "z"
48, // 52 = "0"
49, // 53 = "1"
50, // 54 = "2"
51, // 55 = "3"
52, // 56 = "4"
53, // 57 = "5"
54, // 58 = "6"
55, // 59 = "7"
56, // 60 = "8"
57, // 61 = "9"
45, // 62 = "-"
95, // 63 = "_"
]
private static let safeAlphabetToIndex: [UInt8 : UInt8] = [
61 : 0, // Padding = 0
65 : 0, // 0 = "A"
66 : 1, // 1 = "B"
67 : 2, // 2 = "C"
68 : 3, // 3 = "D"
69 : 4, // 4 = "E"
70 : 5, // 5 = "F"
71 : 6, // 6 = "G"
72 : 7, // 7 = "H"
73 : 8, // 8 = "I"
74 : 9, // 9 = "J"
75 : 10, // 10 = "K"
76 : 11, // 11 = "L"
77 : 12, // 12 = "M"
78 : 13, // 13 = "N"
79 : 14, // 14 = "O"
80 : 15, // 15 = "P"
81 : 16, // 16 = "Q"
82 : 17, // 17 = "R"
83 : 18, // 18 = "S"
84 : 19, // 19 = "T"
85 : 20, // 20 = "U"
86 : 21, // 21 = "V"
87 : 22, // 22 = "W"
88 : 23, // 23 = "X"
89 : 24, // 24 = "Y"
90 : 25, // 25 = "Z"
97 : 26, // 26 = "a"
98 : 27, // 27 = "b"
99 : 28, // 28 = "c"
100 : 29, // 29 = "d"
101 : 30, // 30 = "e"
102 : 31, // 31 = "f"
103 : 32, // 32 = "g"
104 : 33, // 33 = "h"
105 : 34, // 34 = "i"
106 : 35, // 35 = "j"
107 : 36, // 36 = "k"
108 : 37, // 37 = "l"
109 : 38, // 38 = "m"
110 : 39, // 39 = "n"
111 : 40, // 40 = "o"
112 : 41, // 41 = "p"
113 : 42, // 42 = "q"
114 : 43, // 43 = "r"
115 : 44, // 44 = "s"
116 : 45, // 45 = "t"
117 : 46, // 46 = "u"
118 : 47, // 47 = "v"
119 : 48, // 48 = "w"
120 : 49, // 49 = "x"
121 : 50, // 50 = "y"
122 : 51, // 51 = "z"
48 : 52, // 52 = "0"
49 : 53, // 53 = "1"
50 : 54, // 54 = "2"
51 : 55, // 55 = "3"
52 : 56, // 56 = "4"
53 : 57, // 57 = "5"
54 : 58, // 58 = "6"
55 : 59, // 59 = "7"
56 : 60, // 60 = "8"
57 : 61, // 61 = "9"
45 : 62, // 62 = "-"
95 : 63, // 63 = "_"
]
public static func encodeString(str: String) -> String {
// Get the ascii representation and return
let data = str.data(using: .ascii)!
let encData = encode(data: [UInt8](data))
let retStr = String(data: Data(encData), encoding: .ascii)!
return retStr
}
public static func encode(data: [UInt8]) -> [UInt8] {
var result: [UInt8] = []
let size = data.count
// Step through 3 bytes at a time
for i in stride(from: 0, to: size, by: 3) {
// Get the first 6 bits, and add the Base64 letter
let first = data[i] >> 2
result.append(filenameSafeAlphabet[Int(first)])
// Get the remaining 2 bits from the previous byte
var second = (data[i] & 0b11) << 4
// If there is more of the array, add the next 4 bits from byte 2, or return with padding for the 3rd and 4th characters
if i + 1 < size {
second |= (data[i + 1] & 0b11110000) >> 4
result.append(filenameSafeAlphabet[Int(second)])
} else {
result.append(filenameSafeAlphabet[Int(second)])
result.append(padding)
result.append(padding)
return result
}
// Get the remaining 4 bits from the previous byte
var third = (data[i + 1] & 0b1111) << 2
// If there is more of the array, add the next 2 bits from byte 3, or return with padding for the 4th character
if i + 2 < size {
third |= (data[i + 2] & 0b11000000) >> 6
result.append(filenameSafeAlphabet[Int(third)])
} else {
result.append(filenameSafeAlphabet[Int(third)])
result.append(padding)
return result
}
// Get the remaining 6 bits from the previous byte, add to the result
let forth = data[i + 2] & 0b00111111
result.append(filenameSafeAlphabet[Int(forth)])
}
return result
}
public static func decode(data: [UInt8]) -> [UInt8] {
var result: [UInt8] = []
let size = data.count
// We loop over the 4 letters at a time
// We know it is padded, so we dont need to check for size
for i in stride(from: 0, to: size, by: 4) {
// Get the 4 letters, then get back to their non-index values
let first = safeAlphabetToIndex[data[i]]!
let second = safeAlphabetToIndex[data[i + 1]]!
let third = safeAlphabetToIndex[data[i + 2]]!
let forth = safeAlphabetToIndex[data[i + 3]]!
// Get the 3 binary letters from the four 6-bit ones
let l1 = first << 2 | ((second & 0b110000) >> 4)
let l2 = ((second & 0b1111) << 4) | ((third & 0b111100) >> 2)
let l3 = ((third & 0b11) << 6) | forth
// Return the letters if they arent empty
result.append(l1)
if l3 != 0 {
result.append(l2)
result.append(l3)
} else if l2 != 0 {
result.append(l2)
}
}
return result
}
public static func decodeString(str: String) -> String {
// Get the ascii representation and return
let data = str.data(using: .ascii)!
let decData = decode(data: [UInt8](data))
let retStr = String(data: Data(decData), encoding: .ascii)!
return retStr
}
}

View File

@ -0,0 +1,10 @@
import Foundation
enum Constants {
static let googleAuthURL = "https://accounts.google.com/o/oauth2/v2/auth"
static let googleTokenURL = "https://oauth2.googleapis.com/token"
static let googleRedirectURL = "com.googleusercontent.apps.994679674451-k7clunkk4nicl6iuajdtc5u7hvustbdb:/oauth2callback"
static let googleClientId = "994679674451-k7clunkk4nicl6iuajdtc5u7hvustbdb.apps.googleusercontent.com"
static let googleApiKey = "AIzaSyDVlrQj_05y6AeZNf8enpSWFIiHhgwfnGI"
}

View File

@ -0,0 +1,2 @@
import Foundation