diff --git a/TraccarClient.xcodeproj/project.pbxproj b/TraccarClient.xcodeproj/project.pbxproj index 80a92fe5a6a4665e577e0797a25a8182d7bf60ac..e92893d0a4ea2bfb666bd1f56a2a962b10997463 100644 --- a/TraccarClient.xcodeproj/project.pbxproj +++ b/TraccarClient.xcodeproj/project.pbxproj @@ -1304,7 +1304,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = Z7STA3KGEU; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -1479,7 +1479,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = Z7STA3KGEU; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -1516,7 +1516,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 6; + CURRENT_PROJECT_VERSION = 9; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = Z7STA3KGEU; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; diff --git a/TraccarClient.xcodeproj/project.xcworkspace/xcuserdata/g.makhoul.xcuserdatad/UserInterfaceState.xcuserstate b/TraccarClient.xcodeproj/project.xcworkspace/xcuserdata/g.makhoul.xcuserdatad/UserInterfaceState.xcuserstate index f4c147ef0d056e759915734e99eb87884e1b0818..8cfa6510cfbcd4a47da9ed08747c9b0ab73be433 100644 Binary files a/TraccarClient.xcodeproj/project.xcworkspace/xcuserdata/g.makhoul.xcuserdatad/UserInterfaceState.xcuserstate and b/TraccarClient.xcodeproj/project.xcworkspace/xcuserdata/g.makhoul.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/TraccarClient/Custom/KNButtonView/KNButtonView.swift b/TraccarClient/Custom/KNButtonView/KNButtonView.swift index 884c6d6309f700e06f9c907d03700c75599cae44..1d963c7bae068cee7c9efb283a0b827f0de76e5c 100644 --- a/TraccarClient/Custom/KNButtonView/KNButtonView.swift +++ b/TraccarClient/Custom/KNButtonView/KNButtonView.swift @@ -176,9 +176,9 @@ final class KNButtonView: KNComponentView { private func updatePrimary() { boxView.addCorners(cornerRadius) - boxView.backgroundColor = color - titleColor = .white - + boxView.backgroundColor = style == .transparent ? .clear : color + titleColor = style == .transparent ? color : .white + addBorder(radius: 10, width: style == .transparent ? 2 : 0, color: style == .transparent ? color : .white) button.set(localized: title, color: titleColor, font: titleFont) } diff --git a/TraccarClient/Custom/KNButtonView/KNButtonViewHelper.swift b/TraccarClient/Custom/KNButtonView/KNButtonViewHelper.swift index 654f7c802dfbd922f7aa10e61aaf8bfb8ce8b2be..d37f49e3b73d5745c1ebb1b4a1366ebbfa73203f 100644 --- a/TraccarClient/Custom/KNButtonView/KNButtonViewHelper.swift +++ b/TraccarClient/Custom/KNButtonView/KNButtonViewHelper.swift @@ -53,6 +53,7 @@ enum KNButtonViewAction { case retryPayment case addSizeVariantField case addColorVariantField + case loginAsLeader } enum KNButtonViewStyle { diff --git a/TraccarClient/Globals.swift b/TraccarClient/Globals.swift index af5e047f604290fdca27a07bff281fed6bd5269d..7e39a69802888fd5f1159337905d985947eebb26 100644 --- a/TraccarClient/Globals.swift +++ b/TraccarClient/Globals.swift @@ -24,6 +24,15 @@ func main(_ completion: @escaping () -> ()) { } } +var fleetUrl: String { + switch app.environment { + case .development, .sandbox: + return "https://dev-fleet-api.nmo.ai/" + case .production: + return "https://fleet-api.nmo.ai/" + } +} + // MARK: - Global Custom AlertView typealias AlertViewClosure = () -> () diff --git a/TraccarClient/InitialViewController/Controller/InitialViewController.swift b/TraccarClient/InitialViewController/Controller/InitialViewController.swift index 8384c65e69b0d5c363f1d0885eb4dd493a02fc4c..f047571f3afc67d56e0c737c2f09e9bdbcf08944 100644 --- a/TraccarClient/InitialViewController/Controller/InitialViewController.swift +++ b/TraccarClient/InitialViewController/Controller/InitialViewController.swift @@ -9,6 +9,14 @@ import UIKit import Lottie +enum shiftStatus: String { + case notStart + case inProgress + case end + case failed + case none +} + final class InitialViewController: KNViewController { // MARK: - Outlets @IBOutlet weak var animationView: LottieAnimationView! @@ -17,7 +25,8 @@ final class InitialViewController: KNViewController { private let animationFileName: String = "splash" var window: UIWindow? private var shift: ShiftModel? - + let userDefaults = UserDefaults.standard + // MARK: - LifeCycle override func viewDidLoad() { super.viewDidLoad() @@ -36,7 +45,72 @@ final class InitialViewController: KNViewController { override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() } + + func checkShiftStatus(startsAt: String, endsAt: String) -> shiftStatus { + if userDefaults.bool(forKey: Keys.User.autoTracking) == true { + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "HH:mm" + dateFormatter.locale = Locale(identifier: "en_US_POSIX") // Add this line + + guard let shiftStart = dateFormatter.date(from: startsAt), + let shiftEnd = dateFormatter.date(from: endsAt) else { + print("Invalid shift time format.") + return .failed + } + + let calendar = Calendar.current + let currentTime = Date() + let currentComponents = calendar.dateComponents([.hour, .minute], from: currentTime) + let startComponents = calendar.dateComponents([.hour, .minute], from: shiftStart) + let endComponents = calendar.dateComponents([.hour, .minute], from: shiftEnd) + + guard let currentHour = currentComponents.hour, let currentMinute = currentComponents.minute, + let startHour = startComponents.hour, let startMinute = startComponents.minute, + let endHour = endComponents.hour, let endMinute = endComponents.minute else { + print("Failed to extract hour and minute components.") + return .failed + } + + if currentHour < startHour || (currentHour == startHour && currentMinute < startMinute) { + return .notStart + } else if currentHour > endHour || (currentHour == endHour && currentMinute > endMinute) { + return .end + } else { + return .inProgress + } + } + else { + return .none + } + } + + func navigationMethod (by shift: ShiftModel) { + + let shiftStart = shift.timings[0].startsAt + let shiftEnd = shift.timings[0].endsAt + + print("shiftStart: \(shiftStart)") + print("shiftEnds: \(shiftEnd)") + + let shiftStatus = checkShiftStatus(startsAt: shiftStart, endsAt: shiftEnd) + + switch shiftStatus { + case .failed: + print("time formate error") + case .notStart, .inProgress, .end, .none: + let connect = ConnectViewController() + connect.shift = shift + connect.shiftStatus = shiftStatus + let navigation = KNNavigationController(rootViewController: connect) + navigation.modalPresentationStyle = .overFullScreen + + window?.rootViewController = navigation + window?.makeKeyAndVisible() + } + } } + // MARK: - Methods extension InitialViewController { func navigateTo() { @@ -64,14 +138,8 @@ extension InitialViewController { api.permissions { result in if result.success { api.parameters { result in - if result.success { - let connect = ConnectViewController() - connect.shift = strongSelf.shift - let navigation = KNNavigationController(rootViewController: connect) - navigation.modalPresentationStyle = .overFullScreen - - strongSelf.window?.rootViewController = navigation - strongSelf.window?.makeKeyAndVisible() + if result.success { + strongSelf.navigationMethod(by: shift) } else { ok(result) } diff --git a/TraccarClient/LoginViewController/Model/LoginDataProvider.swift b/TraccarClient/LoginViewController/Model/LoginDataProvider.swift index f074def9715fc3086a39c2973476943d475596f6..ad2b10cb608df5ddce6ee2778a5260605024c6e8 100644 --- a/TraccarClient/LoginViewController/Model/LoginDataProvider.swift +++ b/TraccarClient/LoginViewController/Model/LoginDataProvider.swift @@ -35,7 +35,7 @@ final class LoginDataProvider { let space = KNField { field in field.type = .empty - field.height = 30 + field.height = 20 } let loginButton = KNField { field in @@ -44,13 +44,28 @@ final class LoginDataProvider { field.action = .tap field.height = 51 } + + let space1 = KNField { field in + field.type = .empty + field.height = 20 + } + + let leaderLogin = KNField { field in + field.type = .button + field.style = .transparent + field.title = "Login as a Leader" + field.action = .loginAsLeader + field.height = 51 + } fields = [ domain, email, password, space, - loginButton + loginButton, +// space1, +// leaderLogin ] return fields } diff --git a/TraccarClient/LoginViewController/Model/LoginDataSource.swift b/TraccarClient/LoginViewController/Model/LoginDataSource.swift index d82dbbd59cc6d45ab7b9ab94ed72a5f2db19fe5a..608a26655fa2e2d1956ecda6ccfd70b9c3a77af9 100644 --- a/TraccarClient/LoginViewController/Model/LoginDataSource.swift +++ b/TraccarClient/LoginViewController/Model/LoginDataSource.swift @@ -37,6 +37,7 @@ extension LoginDataSource: UITableViewDelegate, UITableViewDataSource { cell.set(field: field, indexPath: indexPath) return cell } + if field.type == .button { let cell = tableView.dequeue(withCell: ButtonTableViewCell.self) cell.delegate = self diff --git a/TraccarClient/LoginViewController/Model/LoginModelController.swift b/TraccarClient/LoginViewController/Model/LoginModelController.swift index 3a0ef6cd26d518a60c9651cd8642c6bdaa6a2c4d..d42dad699b30efe6b4882253711122bb51547314 100644 --- a/TraccarClient/LoginViewController/Model/LoginModelController.swift +++ b/TraccarClient/LoginViewController/Model/LoginModelController.swift @@ -68,7 +68,7 @@ final class LoginModelController { for item in fields { if item.field == .domain { UserDefaults.standard.set("\(item.value.value).nmo.ai", forKey: "xcompany") - UserDefaults.standard.set("https://dev-fleet-api.nmo.ai/", forKey: "server_url_preference") + UserDefaults.standard.set(fleetUrl, forKey: "server_url_preference") } if item.type == .text && item.field != .domain { params.add(item.field.rawValue, item.value.value) @@ -88,9 +88,15 @@ final class LoginModelController { api.parameters { result in spinner.stop() if result.success { - let connect = ConnectViewController() - connect.shift = strongSelf.shift - strongSelf.viewController.navigationController?.pushViewController(connect, animated: true) + for item in strongSelf.fields { + if item.field == .username { + UserDefaults.standard.set("\(item.value.value)", forKey: "device_id_preference") + strongSelf.setupTracking() + let connect = ConnectViewController() + connect.shift = strongSelf.shift + strongSelf.viewController.navigationController?.pushViewController(connect, animated: true) + } + } } } } @@ -166,7 +172,12 @@ extension LoginModelController { // MARK: - Output Protocol extension LoginModelController: LoginOutputProtocol { func cellButtonTapped(action: KNButtonViewAction) { - signin() + if action == .tap { + signin() + } + if action == .loginAsLeader { + print("hello") + } } func reloadUI() { diff --git a/TraccarClient/LoginViewController/View/LoginViewController.xib b/TraccarClient/LoginViewController/View/LoginViewController.xib index af884bc41a2f44d3b13d1d22a249ff19d4867635..cf0652b16f98ac15684ed15b365311206a8bf5ae 100644 --- a/TraccarClient/LoginViewController/View/LoginViewController.xib +++ b/TraccarClient/LoginViewController/View/LoginViewController.xib @@ -29,26 +29,26 @@ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="DeliveryIcon" translatesAutoresizingMaskIntoConstraints="NO" id="rPb-N8-5pB"> - <rect key="frame" x="116.66666666666669" y="75" width="160" height="160"/> + <rect key="frame" x="116.66666666666669" y="0.0" width="160" height="160"/> <constraints> <constraint firstAttribute="width" constant="160" id="eJs-0H-D6L"/> <constraint firstAttribute="height" constant="160" id="xEg-fV-es4"/> </constraints> </imageView> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Dive into Fleet Tracking!" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jC6-Ly-QKC"> - <rect key="frame" x="81.666666666666671" y="245" width="229.66666666666663" height="22"/> + <rect key="frame" x="81.666666666666671" y="170" width="229.66666666666663" height="22"/> <fontDescription key="fontDescription" name="Montserrat-Bold" family="Montserrat" pointSize="18"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stay connected, drive smart." textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ejG-GP-Evp"> - <rect key="frame" x="111.33333333333333" y="274" width="170.33333333333337" height="14.666666666666686"/> + <rect key="frame" x="111.33333333333333" y="199" width="170.33333333333337" height="14.666666666666657"/> <fontDescription key="fontDescription" name="Montserrat-Regular" family="Montserrat" pointSize="12"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="-1" estimatedSectionHeaderHeight="-1" sectionFooterHeight="-1" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="cqa-qG-jss"> - <rect key="frame" x="32" y="313.66666666666674" width="329" height="472.33333333333326"/> + <rect key="frame" x="32" y="238.66666666666669" width="329" height="547.33333333333326"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/> </tableView> </subviews> @@ -58,7 +58,7 @@ <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="cqa-qG-jss" secondAttribute="trailing" constant="32" id="3jQ-sI-aAm"/> <constraint firstItem="rPb-N8-5pB" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="CJs-Qh-u3u"/> <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="cqa-qG-jss" secondAttribute="bottom" constant="32" id="Dqf-I3-asf"/> - <constraint firstItem="rPb-N8-5pB" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="75" id="HjK-k3-B52"/> + <constraint firstItem="rPb-N8-5pB" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="HjK-k3-B52"/> <constraint firstItem="cqa-qG-jss" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="32" id="bDg-CD-ZNz"/> <constraint firstItem="ejG-GP-Evp" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="nuW-Lh-yVC"/> <constraint firstItem="ejG-GP-Evp" firstAttribute="top" secondItem="jC6-Ly-QKC" secondAttribute="bottom" constant="7" id="o0G-Yj-sgP"/> diff --git a/TraccarClient/MainViewController/ConnectViewController.swift b/TraccarClient/MainViewController/ConnectViewController.swift index 5d7f321478ac8306750951645231e563b37e548d..3b0e22fd3ab25baf647e45f523716ec47623a28b 100644 --- a/TraccarClient/MainViewController/ConnectViewController.swift +++ b/TraccarClient/MainViewController/ConnectViewController.swift @@ -8,6 +8,7 @@ import UIKit //import InAppSettingsKit +import AppTrackingTransparency final class ConnectViewController: KNViewController { // MARK: - Outlets @@ -32,6 +33,7 @@ final class ConnectViewController: KNViewController { var shift: ShiftModel? let timeFormat = "HH:mm" let dateFormatter = DateFormatter() + var shiftStatus: shiftStatus = .failed // MARK: - LifeCycle override func viewDidLoad() { @@ -45,6 +47,30 @@ final class ConnectViewController: KNViewController { } private func setupUI() { + if #available(iOS 14, *) { + ATTrackingManager.requestTrackingAuthorization { status in + switch status { + case .authorized: + print("Tracking Authorized.") + + case .denied: + // Tracking authorization dialog was shown and permission was not granted. + print("Tracking denied.") + case .notDetermined: + // Tracking authorization dialog has not been shown. + print("Tracking not determined.") + case .restricted: + // The device is not eligible for tracking. + print("Tracking restricted.") + @unknown default: + // A new case was added that we're not handling. + print("Unknown case.") + } + } + } else { + // don't do anything + } + setupShiftView() customHeaderView.set(type: .home, delegate: self) timerLabel.text = "" @@ -62,50 +88,14 @@ final class ConnectViewController: KNViewController { } private func setupShiftView() { - if userDefaults.bool(forKey: Keys.User.autoTracking) == true { - dateFormatter.dateFormat = timeFormat - if let targetTime = dateFormatter.date(from: shift?.timings[0].startsAt ?? "") { - if let endTime = dateFormatter.date(from: shift?.timings[0].endsAt ?? "") { - let currentTime = Date() - - let calendar = Calendar.current - let currentComponents = calendar.dateComponents([.hour, .minute], from: currentTime) - let targetComponents = calendar.dateComponents([.hour, .minute], from: targetTime) - let endComponents = calendar.dateComponents([.hour, .minute], from: endTime) - - if let currentHour = currentComponents.hour, let currentMinute = currentComponents.minute, - let targetHour = targetComponents.hour, let targetMinute = targetComponents.minute, let endHour = endComponents.hour, let endMinute = endComponents.minute { - - if currentHour < targetHour || (currentHour == targetHour && currentMinute < targetMinute) { - print("Current time is earlier than 09:00") - trackingView.isHidden = true - shiftsView.isHidden = false - shiftsView.set(model: shift ?? ShiftModel()) - - } else if currentHour > targetHour || (currentHour == targetHour && currentMinute > targetMinute) { - if currentHour < endHour || (currentHour == endHour && currentMinute < endMinute) { - trackingView.isHidden = false - shiftsView.isHidden = true - setupTrackingView() - } else { - shiftsView.isHidden = false - trackingView.isHidden = true - shiftsView.set(model: shift ?? ShiftModel()) - } - } else { - shiftsView.isHidden = true - trackingView.isHidden = false - setupTrackingView() - } - } - } else { - print("Invalid time format") - } - } - else { - print("Invalid time format") - } + + switch shiftStatus { + case .notStart: + trackingView.isHidden = true + shiftsView.isHidden = false + shiftsView.set(model: shift ?? ShiftModel()) + case .inProgress: startTimer() userDefaults.set(true, forKey: "service_status_preference") statusChanged(to: true) @@ -113,10 +103,67 @@ final class ConnectViewController: KNViewController { AppDelegate.instance.trackingController = TrackingController() AppDelegate.instance.trackingController?.start() - } else { + case .end: + trackingView.isHidden = true + shiftsView.isHidden = false + shiftsView.set(model: shift ?? ShiftModel()) + + case .failed: + print("error in time formate") + case .none: shiftsView.isHidden = true trackingView.isHidden = true } + +// if userDefaults.bool(forKey: Keys.User.autoTracking) == true { +// dateFormatter.dateFormat = timeFormat +// if let targetTime = dateFormatter.date(from: shift?.timings[0].startsAt ?? "") { +// if let endTime = dateFormatter.date(from: shift?.timings[0].endsAt ?? "") { +// let currentTime = Date() +// +// let calendar = Calendar.current +// let currentComponents = calendar.dateComponents([.hour, .minute], from: currentTime) +// let targetComponents = calendar.dateComponents([.hour, .minute], from: targetTime) +// let endComponents = calendar.dateComponents([.hour, .minute], from: endTime) +// +// if let currentHour = currentComponents.hour, let currentMinute = currentComponents.minute, +// let targetHour = targetComponents.hour, let targetMinute = targetComponents.minute, let endHour = endComponents.hour, let endMinute = endComponents.minute { +// +// if currentHour < targetHour || (currentHour == targetHour && currentMinute < targetMinute) { +// print("Current time is earlier than 09:00") +// trackingView.isHidden = true +// shiftsView.isHidden = false +// shiftsView.set(model: shift ?? ShiftModel()) +// +// } else if currentHour > targetHour || (currentHour == targetHour && currentMinute > targetMinute) { +// if currentHour < endHour || (currentHour == endHour && currentMinute < endMinute) { +// trackingView.isHidden = false +// shiftsView.isHidden = true +// setupTrackingView() +// } else { +// shiftsView.isHidden = false +// trackingView.isHidden = true +// shiftsView.set(model: shift ?? ShiftModel()) +// } +// } else { +// shiftsView.isHidden = true +// trackingView.isHidden = false +// setupTrackingView() +// } +// } +// } else { +// print("Invalid time format") +// } +// } +// else { +// print("Invalid time format") +// } +// +// +// } else { +// shiftsView.isHidden = true +// trackingView.isHidden = true +// } } private func setupTrackingView() { diff --git a/TraccarClient/TraccarClient-Info.plist b/TraccarClient/TraccarClient-Info.plist index 41e942551b9000f88020b353b162081749276283..fe5270c65354dedf248cbfcb5d9abb4eddbd2412 100644 --- a/TraccarClient/TraccarClient-Info.plist +++ b/TraccarClient/TraccarClient-Info.plist @@ -116,5 +116,7 @@ <string>Light</string> <key>UIViewControllerBasedStatusBarAppearance</key> <false/> + <key>NSUserTrackingUsageDescription</key> + <string>We use your data to provide you with a personalized experience.</string> </dict> </plist>