diff --git a/AutoCat.xcodeproj/project.pbxproj b/AutoCat.xcodeproj/project.pbxproj index 7f9be28..8304e65 100644 --- a/AutoCat.xcodeproj/project.pbxproj +++ b/AutoCat.xcodeproj/project.pbxproj @@ -34,6 +34,7 @@ 7A11474923FF2B2D00B424AF /* Response.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474823FF2B2D00B424AF /* Response.swift */; }; 7A11474B23FF368B00B424AF /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A11474A23FF368B00B424AF /* Settings.swift */; }; 7A15051224DB3E3000F39631 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A15051124DB3E3000F39631 /* AnyEncodable.swift */; }; + 7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */; }; 7A21112A24FC3D7E003BBF6F /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A21112924FC3D7E003BBF6F /* AudioEngine.swift */; }; 7A27ADC7249D43210035F39E /* RegionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADC6249D43210035F39E /* RegionsController.swift */; }; 7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A27ADF2249F8B650035F39E /* RecordsController.swift */; }; @@ -129,6 +130,7 @@ 7A11474A23FF368B00B424AF /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; 7A11474D23FFEE8800B424AF /* SVProgressHUD.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SVProgressHUD.framework; path = Carthage/Build/iOS/SVProgressHUD.framework; sourceTree = ""; }; 7A15051124DB3E3000F39631 /* AnyEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = ""; }; + 7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockBarButtonItem.swift; sourceTree = ""; }; 7A21112924FC3D7E003BBF6F /* AudioEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = ""; }; 7A27ADC6249D43210035F39E /* RegionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegionsController.swift; sourceTree = ""; }; 7A27ADF2249F8B650035F39E /* RecordsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordsController.swift; sourceTree = ""; }; @@ -415,6 +417,7 @@ 7AB67E8D2435D1A000258F61 /* CustomButton.swift */, 7A1090EB24A4E3E100B4F0B2 /* CellProgressView.swift */, 7ADF6C96250F41B000F237B2 /* PNKeyboard.swift */, + 7A1DC38D2517ED98002E9C99 /* BlockBarButtonItem.swift */, ); path = Views; sourceTree = ""; @@ -562,6 +565,7 @@ 7AE26A3524F31B0700625033 /* EventsController.swift in Sources */, 7AB67E8C2435C38700258F61 /* CustomTextField.swift in Sources */, 7A27ADF5249FD2F90035F39E /* FileManagerExt.swift in Sources */, + 7A1DC38E2517ED98002E9C99 /* BlockBarButtonItem.swift in Sources */, 7AE26A3324EEF9EC00625033 /* UIViewControllerExt.swift in Sources */, 7A27ADF3249F8B650035F39E /* RecordsController.swift in Sources */, 7A8A2209248D10EC0073DFD9 /* ResizeImage.swift in Sources */, diff --git a/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 02e91d7..7615455 100644 --- a/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -73,10 +73,10 @@ filePath = "AutoCat/Utils/Api.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "228" - endingLineNumber = "228" + startingLineNumber = "232" + endingLineNumber = "232" landmarkName = "add(event:to:)" - landmarkType = "7"> + landmarkType = "9"> diff --git a/AutoCat/AppDelegate.swift b/AutoCat/AppDelegate.swift index 32cb538..7fd141e 100644 --- a/AutoCat/AppDelegate.swift +++ b/AutoCat/AppDelegate.swift @@ -13,6 +13,7 @@ enum QuickAction { case check case checkNumber(String, VehicleEvent?) case addVoiceRecord + case openReport(String) } @UIApplicationMain diff --git a/AutoCat/AutoCat.entitlements b/AutoCat/AutoCat.entitlements index 8844e35..144ad51 100644 --- a/AutoCat/AutoCat.entitlements +++ b/AutoCat/AutoCat.entitlements @@ -2,9 +2,9 @@ - com.apple.developer.applesignin + com.apple.developer.associated-domains - Default + applinks:auto.aliencat.pro com.apple.security.app-sandbox diff --git a/AutoCat/Controllers/CheckController.swift b/AutoCat/Controllers/CheckController.swift index fff8317..0cfb280 100644 --- a/AutoCat/Controllers/CheckController.swift +++ b/AutoCat/Controllers/CheckController.swift @@ -99,6 +99,12 @@ class CheckController: UIViewController, UITableViewDelegate, UITextFieldDelegat case .addVoiceRecord: self.tabBarController?.selectedIndex = 1 break + case .openReport(let number): + ad.quickAction = .none + if let sd = self.view.window?.windowScene?.delegate as? SceneDelegate { + sd.openReport(with: number) + } + break default: break } diff --git a/AutoCat/Controllers/ReportController.swift b/AutoCat/Controllers/ReportController.swift index 7dfa227..5229127 100644 --- a/AutoCat/Controllers/ReportController.swift +++ b/AutoCat/Controllers/ReportController.swift @@ -421,7 +421,7 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti let shareLink = UIAlertAction(title: "As link", style: .default) { _ in guard let vehicle = self.vehicle else { return } - if let jwt = try? JWT.generate(for: vehicle.number), let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt) { + if let jwt = try? JWT.generate(for: vehicle.number), let url = URL(string: Constants.reportLinkBaseURL + "?token=" + jwt) { let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil) controller.popoverPresentationController?.barButtonItem = sender self.present(controller, animated: true) diff --git a/AutoCat/Controllers/SettingsController.swift b/AutoCat/Controllers/SettingsController.swift index a1f2f36..ee77b97 100644 --- a/AutoCat/Controllers/SettingsController.swift +++ b/AutoCat/Controllers/SettingsController.swift @@ -14,7 +14,7 @@ class SettingsController: FormViewController { } <<< LabelRow("GoogleAccount") { row in row.title = "Google" - if let jwtString = Settings.shared.user.firebaseIdToken, let jwt = JWT(string: jwtString) { + if let jwtString = Settings.shared.user.firebaseIdToken, let jwt = JWT(string: jwtString) { row.value = jwt.payload.email } else { row.value = "Log In" @@ -92,7 +92,7 @@ class SettingsController: FormViewController { } func displayLogoutSheet(for row: String) { - guard let jwtString = Settings.shared.user.firebaseIdToken, let jwt = JWT(string: jwtString) else { return } + guard let jwtString = Settings.shared.user.firebaseIdToken, let jwt = JWT(string: jwtString) else { return } let sheet = UIAlertController(title: jwt.payload.name, message: "You are currently signed in with email \(jwt.payload.email). It will help to gather more data about vehicles.", preferredStyle: .actionSheet) @@ -116,7 +116,7 @@ class SettingsController: FormViewController { if let vc = storyboard.instantiateViewController(identifier: "GoogleSignInController") as? GoogleSignInController { vc.completion = { guard let googleRow = self.form.rowBy(tag: "GoogleAccount") as? LabelRow else { return } - if let jwtString = Settings.shared.user.firebaseIdToken, let jwt = JWT(string: jwtString) { + if let jwtString = Settings.shared.user.firebaseIdToken, let jwt = JWT(string: jwtString) { googleRow.value = jwt.payload.email } else { googleRow.value = "Log In" diff --git a/AutoCat/SceneDelegate.swift b/AutoCat/SceneDelegate.swift index 7e4daa6..50a0162 100644 --- a/AutoCat/SceneDelegate.swift +++ b/AutoCat/SceneDelegate.swift @@ -1,6 +1,7 @@ import UIKit import os.log import AVFoundation +import RxSwift class SceneDelegate: UIResponder, UIWindowSceneDelegate { @@ -17,6 +18,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { if activity.activityType == "pro.aliencat.autocat.addVoiceRecord" { ad.quickAction = .addVoiceRecord } + + if let url = activity.webpageURL { + if let param = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.first, let token = param.value { + if let jwt = JWT(string: token) { + ad.quickAction = .openReport(jwt.payload.plateNumber) + } + } + } } self.window = UIWindow(windowScene: windowScene) @@ -104,6 +113,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { if userActivity.activityType == "pro.aliencat.autocat.addVoiceRecord" { self.handleAddVoiceRecordAction() } + + if let url = userActivity.webpageURL { + if let param = URLComponents(url: url, resolvingAgainstBaseURL: false)?.queryItems?.first, let token = param.value { + if let jwt = JWT(string: token) { + self.openReport(with: jwt.payload.plateNumber) + } + } + } } func handleAddVoiceRecordAction() { @@ -124,5 +141,23 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } } } + + func openReport(with number: String) { + guard let rootController = self.window?.rootViewController else { return } + + IHProgressHUD.show() + _ = Api.getReport(for: number).observeOn(MainScheduler.instance).subscribe { vehicle in + let sb = UIStoryboard(name: "Main", bundle: nil) + let controller = sb.instantiateViewController(identifier: "ReportController") as ReportController + controller.vehicle = vehicle + let nav = UINavigationController(rootViewController: controller) + nav.modalPresentationStyle = .fullScreen + controller.navigationItem.leftBarButtonItem = BlockBarButtonItem(barButtonSystemItem: .close) { _ in nav.dismiss(animated: true) } + rootController.present(nav, animated: true) + IHProgressHUD.dismiss() + } onError: { error in + IHProgressHUD.show(error: error) + } + } } diff --git a/AutoCat/Utils/Api.swift b/AutoCat/Utils/Api.swift index 94befd9..6b7a098 100644 --- a/AutoCat/Utils/Api.swift +++ b/AutoCat/Utils/Api.swift @@ -80,7 +80,7 @@ class Api { // MARK: - Firebase API public static func refreshFbToken() -> Single { - guard let token = Settings.shared.user.firebaseIdToken, let refreshToken = Settings.shared.user.firebaseRefreshToken, let jwt = JWT(string: token), jwt.expired else { + guard let token = Settings.shared.user.firebaseIdToken, let refreshToken = Settings.shared.user.firebaseRefreshToken, let jwt = JWT(string: token), jwt.expired else { return .just(()) } @@ -208,6 +208,10 @@ class Api { } } + public static func getReport(for number: String) -> Single { + return self.makeGetRequest(api: "vehicles/report", params: ["number": number]) + } + public static func getBrands() -> Single<[String]> { return self.makeEmptyGetRequest(api: "vehicles/brands") } diff --git a/AutoCat/Utils/Constants.swift b/AutoCat/Utils/Constants.swift index fd8bd02..34e7169 100644 --- a/AutoCat/Utils/Constants.swift +++ b/AutoCat/Utils/Constants.swift @@ -3,9 +3,9 @@ import Foundation enum Constants { static var baseUrl: String { #if DEBUG - //return "http://127.0.0.1:3000/" + return "http://127.0.0.1:3000/" //return "http://192.168.1.67:3000/" - return "https://vps.aliencat.pro:8443/" + //return "https://vps.aliencat.pro:8443/" #else return "https://vps.aliencat.pro:8443/" #endif diff --git a/AutoCat/Utils/JWT.swift b/AutoCat/Utils/JWT.swift index 12543bb..151cd04 100644 --- a/AutoCat/Utils/JWT.swift +++ b/AutoCat/Utils/JWT.swift @@ -61,15 +61,28 @@ extension String { } } -struct JwtPayload: Codable { - var email: String - var name: String - var exp: Int +protocol JwtPayload: Codable { + var exp: Int { get } } -class JWT { +extension JwtPayload { + var exp: Int { 0 } +} + +struct EmptyPayload: JwtPayload { } + +struct FirebasePayload: JwtPayload { + var email: String + var name: String +} + +struct NumberPayload: JwtPayload { + var plateNumber: String +} + +class JWT where T: JwtPayload { private var jwt: String - public let payload: JwtPayload + public let payload: T public var expired: Bool { return TimeInterval(self.payload.exp) < Date().timeIntervalSince1970 } @@ -80,13 +93,14 @@ class JWT { let parts = string.split(separator: ".") if parts.count == 3 { var payloadStr = String(parts[1]) - if (payloadStr.count % 2 != 0) { - payloadStr += String(repeating: "=", count: (payloadStr.count % 2)) + if (payloadStr.count % 4 != 0) { + payloadStr += String(repeating: "=", count: (payloadStr.count % 4)) } if let json = Data(base64Encoded: payloadStr, options: [.ignoreUnknownCharacters]) { - if let resp = try? JSONDecoder().decode(JwtPayload.self, from: json) { - self.payload = resp - } else { + do { + self.payload = try JSONDecoder().decode(T.self, from: json) + } catch { + print(error) return nil } } else { diff --git a/AutoCat/Views/BlockBarButtonItem.swift b/AutoCat/Views/BlockBarButtonItem.swift new file mode 100644 index 0000000..4672c57 --- /dev/null +++ b/AutoCat/Views/BlockBarButtonItem.swift @@ -0,0 +1,29 @@ +import UIKit + +class BlockBarButtonItem: UIBarButtonItem { + typealias ActionHandler = (UIBarButtonItem) -> Void + + private var actionHandler: ActionHandler? + + convenience init(image: UIImage?, style: UIBarButtonItem.Style, actionHandler: ActionHandler?) { + self.init(image: image, style: style, target: nil, action: #selector(barButtonItemPressed(sender:))) + target = self + self.actionHandler = actionHandler + } + + convenience init(title: String?, style: UIBarButtonItem.Style, actionHandler: ActionHandler?) { + self.init(title: title, style: style, target: nil, action: #selector(barButtonItemPressed(sender:))) + target = self + self.actionHandler = actionHandler + } + + convenience init(barButtonSystemItem systemItem: UIBarButtonItem.SystemItem, actionHandler: ActionHandler?) { + self.init(barButtonSystemItem: systemItem, target: nil, action: #selector(barButtonItemPressed(sender:))) + target = self + self.actionHandler = actionHandler + } + + @objc func barButtonItemPressed(sender: UIBarButtonItem) { + actionHandler?(sender) + } +}