diff --git a/TraccarClient.xcodeproj/project.pbxproj b/TraccarClient.xcodeproj/project.pbxproj index 8cbe72ed35d8a44db17fceb3d4fcbe478648fcea..35ab939b81ef2f19195108db2b27f824b55cedf7 100644 --- a/TraccarClient.xcodeproj/project.pbxproj +++ b/TraccarClient.xcodeproj/project.pbxproj @@ -115,6 +115,8 @@ 53B6DB7D2B611C12000C1083 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 53B6DB7C2B611C12000C1083 /* GoogleService-Info.plist */; }; 53B6DB7F2B61371A000C1083 /* LeaderNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53B6DB7E2B61371A000C1083 /* LeaderNavigationView.swift */; }; 53B6DB822B61376B000C1083 /* LeaderNavigationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53B6DB812B61376B000C1083 /* LeaderNavigationView.xib */; }; + 53B6DB862B664287000C1083 /* AlertViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53B6DB842B664287000C1083 /* AlertViewController.swift */; }; + 53B6DB872B664287000C1083 /* AlertViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53B6DB852B664287000C1083 /* AlertViewController.xib */; }; 53D62E3F2AEFA31200C80BAC /* InitialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D62E3D2AEFA31200C80BAC /* InitialViewController.swift */; }; 53D62E402AEFA31200C80BAC /* InitialViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53D62E3E2AEFA31200C80BAC /* InitialViewController.xib */; }; 53D62E432AEFA4DC00C80BAC /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = 53D62E422AEFA4DC00C80BAC /* Lottie */; }; @@ -299,6 +301,8 @@ 53B6DB7C2B611C12000C1083 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; }; 53B6DB7E2B61371A000C1083 /* LeaderNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeaderNavigationView.swift; sourceTree = "<group>"; }; 53B6DB812B61376B000C1083 /* LeaderNavigationView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LeaderNavigationView.xib; sourceTree = "<group>"; }; + 53B6DB842B664287000C1083 /* AlertViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertViewController.swift; sourceTree = "<group>"; }; + 53B6DB852B664287000C1083 /* AlertViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlertViewController.xib; sourceTree = "<group>"; }; 53D62E3D2AEFA31200C80BAC /* InitialViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialViewController.swift; sourceTree = "<group>"; }; 53D62E3E2AEFA31200C80BAC /* InitialViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = InitialViewController.xib; sourceTree = "<group>"; }; 53EBC5FC2AF199FF00601AA7 /* SettingsTextTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTextTableViewCell.swift; sourceTree = "<group>"; }; @@ -672,6 +676,7 @@ 532683C42AEA5DB000A364C0 /* Controllers */ = { isa = PBXGroup; children = ( + 53B6DB832B66425E000C1083 /* AlertViewController */, 530080352AF15CC400A05E04 /* TransactionsViewController */, 5300802B2AF149C500A05E04 /* SettingsViewController */, 53F10AF12AF0F267004D0529 /* MainViewController */, @@ -752,6 +757,15 @@ name = CustomView; sourceTree = "<group>"; }; + 53B6DB832B66425E000C1083 /* AlertViewController */ = { + isa = PBXGroup; + children = ( + 53B6DB842B664287000C1083 /* AlertViewController.swift */, + 53B6DB852B664287000C1083 /* AlertViewController.xib */, + ); + path = AlertViewController; + sourceTree = "<group>"; + }; 53D62E3C2AEFA2F800C80BAC /* InitialViewController */ = { isa = PBXGroup; children = ( @@ -1091,6 +1105,7 @@ 530080392AF15CE000A05E04 /* TransactionsViewController.xib in Resources */, 53200CF32B60FB5800D1445D /* LeaderViewController.xib in Resources */, 53A306232B0CAF7800FAEA00 /* TrackingView.xib in Resources */, + 53B6DB872B664287000C1083 /* AlertViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1183,6 +1198,7 @@ 5E716A2B1F63A60800A2DBC3 /* ProtocolFormatter.swift in Sources */, 53F10AE62AF05E97004D0529 /* AuthenticationCoordinator.swift in Sources */, 532683772AE923A500A364C0 /* KNTextFieldView.swift in Sources */, + 53B6DB862B664287000C1083 /* AlertViewController.swift in Sources */, 53157ECC2AEE55AB003C9B6A /* KNViewController.swift in Sources */, 53554ADF2AED1B480018BAEE /* KNButtonView.swift in Sources */, 53157EC62AEE4076003C9B6A /* UserModel.swift in Sources */, @@ -1349,7 +1365,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = Z7STA3KGEU; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -1525,7 +1541,7 @@ CODE_SIGN_ENTITLEMENTS = TraccarClient/TraccarClient.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = Z7STA3KGEU; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -1563,7 +1579,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; 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 4a0b837f0ed7a6ab3b29628648c9aca0c4e86705..f689226b98fea0067d78720c8f3aa39ceb185807 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/AlertViewController/AlertViewController.swift b/TraccarClient/AlertViewController/AlertViewController.swift new file mode 100644 index 0000000000000000000000000000000000000000..b87e7343c0f2b810111eefe6936b1ebff67b09ad --- /dev/null +++ b/TraccarClient/AlertViewController/AlertViewController.swift @@ -0,0 +1,33 @@ +// +// AlertViewController.swift +// TraccarClient +// +// Created by George Makhoul on 28/01/2024. +// Copyright © 2024 Traccar. All rights reserved. +// + +import UIKit + +class AlertViewController: KNViewController { + // MARK: - Outlets + @IBOutlet weak var proceedButton: UIButton! + + // MARK: - Properties + var window: UIWindow? + var shift: ShiftModel? + var shiftStatus: shiftStatus = .failed + + // MARK: - LifeCycle + override func viewDidLoad() { + super.viewDidLoad() + hasCustomNavigation = true + proceedButton.addCorners(10) + } + + @IBAction func proceedButton(_ sender: UIButton) { + let connect = ConnectViewController() + connect.shift = shift + connect.shiftStatus = shiftStatus + navigationController?.pushViewController(connect, animated: true) + } +} diff --git a/TraccarClient/AlertViewController/AlertViewController.xib b/TraccarClient/AlertViewController/AlertViewController.xib new file mode 100644 index 0000000000000000000000000000000000000000..88e9c9b5dbd94534e12d47eb76d03578bf7586e0 --- /dev/null +++ b/TraccarClient/AlertViewController/AlertViewController.xib @@ -0,0 +1,105 @@ +<?xml version="1.0" encoding="UTF-8"?> +<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22155" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> + <device id="retina6_72" orientation="portrait" appearance="light"/> + <dependencies> + <deployment identifier="iOS"/> + <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22131"/> + <capability name="Safe area layout guides" minToolsVersion="9.0"/> + <capability name="System colors in document resources" minToolsVersion="11.0"/> + <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> + </dependencies> + <customFonts key="customFonts"> + <array key="Montserrat-Bold.ttf"> + <string>Montserrat-Bold</string> + </array> + <array key="Montserrat-Regular.ttf"> + <string>Montserrat-Regular</string> + </array> + </customFonts> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AlertViewController" customModule="TraccarClient" customModuleProvider="target"> + <connections> + <outlet property="proceedButton" destination="yX4-N7-Of4" id="OAo-s9-OWv"/> + <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> + </connections> + </placeholder> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT"> + <rect key="frame" x="0.0" y="0.0" width="430" height="932"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="nmoLogo" translatesAutoresizingMaskIntoConstraints="NO" id="SV6-jI-GsX"> + <rect key="frame" x="140" y="90" width="150" height="150"/> + <constraints> + <constraint firstAttribute="width" constant="150" id="LSU-dY-aev"/> + <constraint firstAttribute="height" constant="150" id="RrD-na-H8n"/> + </constraints> + </imageView> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Looks like you're joining us a bit late today!" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gEz-ya-2Zl"> + <rect key="frame" x="17" y="257" width="396" height="27"/> + <fontDescription key="fontDescription" name="Montserrat-Bold" family="Montserrat" pointSize="14"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="alertIcon" translatesAutoresizingMaskIntoConstraints="NO" id="Wti-X9-j6T"> + <rect key="frame" x="42" y="341" width="346" height="176"/> + <constraints> + <constraint firstAttribute="height" constant="176" id="JwW-Kc-5Qe"/> + </constraints> + </imageView> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="wb6-Yw-ChF"> + <rect key="frame" x="29" y="580" width="372" height="110"/> + <constraints> + <constraint firstAttribute="height" constant="110" id="6T1-xp-8VL"/> + </constraints> + <string key="text">No worries! Your tracking has started now and will continue for the remainder of your shift. Let's make the rest of the day count! ⏰✨</string> + <fontDescription key="fontDescription" name="Montserrat-Regular" family="Montserrat" pointSize="16"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yX4-N7-Of4"> + <rect key="frame" x="32" y="854.33333333333337" width="366" height="51"/> + <color key="backgroundColor" red="0.38431372549999998" green="0.21960784310000001" blue="0.62352941179999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <constraints> + <constraint firstAttribute="height" constant="51" id="Cqv-0o-ZpA"/> + </constraints> + <fontDescription key="fontDescription" type="boldSystem" pointSize="18"/> + <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> + <state key="normal" title="PROCEED"> + <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </state> + <connections> + <action selector="proceedButton:" destination="-1" eventType="touchUpInside" id="Zt8-vB-X1q"/> + </connections> + </button> + </subviews> + <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <constraints> + <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="wb6-Yw-ChF" secondAttribute="trailing" constant="29" id="0zG-U4-HiH"/> + <constraint firstItem="gEz-ya-2Zl" firstAttribute="top" secondItem="SV6-jI-GsX" secondAttribute="bottom" constant="17" id="5XO-FV-Fb0"/> + <constraint firstItem="Wti-X9-j6T" firstAttribute="top" secondItem="gEz-ya-2Zl" secondAttribute="bottom" constant="57" id="7Dw-dV-mT5"/> + <constraint firstItem="SV6-jI-GsX" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="90" id="A4G-yR-hs0"/> + <constraint firstItem="wb6-Yw-ChF" firstAttribute="top" secondItem="Wti-X9-j6T" secondAttribute="bottom" constant="63" id="Awx-cm-0at"/> + <constraint firstItem="wb6-Yw-ChF" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="29" id="BIF-JK-pqa"/> + <constraint firstItem="Wti-X9-j6T" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="42" id="CKC-zV-C8Y"/> + <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="yX4-N7-Of4" secondAttribute="trailing" constant="32" id="Kl4-2k-BGn"/> + <constraint firstItem="yX4-N7-Of4" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="32" id="Noc-Sz-550"/> + <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="gEz-ya-2Zl" secondAttribute="trailing" constant="17" id="WbD-et-RGp"/> + <constraint firstAttribute="bottom" secondItem="yX4-N7-Of4" secondAttribute="bottom" constant="26.670000000000002" id="ZPl-r5-FGT"/> + <constraint firstItem="SV6-jI-GsX" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="h5r-Jz-27c"/> + <constraint firstItem="yX4-N7-Of4" firstAttribute="top" relation="lessThanOrEqual" secondItem="wb6-Yw-ChF" secondAttribute="bottom" constant="164.33000000000001" id="pkX-do-tXl"/> + <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="Wti-X9-j6T" secondAttribute="trailing" constant="42" id="w5d-hh-ioW"/> + <constraint firstItem="gEz-ya-2Zl" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="17" id="wck-Ej-sXu"/> + </constraints> + <point key="canvasLocation" x="-53" y="21"/> + </view> + </objects> + <resources> + <image name="alertIcon" width="311" height="176"/> + <image name="nmoLogo" width="165" height="165"/> + <systemColor name="systemBackgroundColor"> + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </systemColor> + </resources> +</document> diff --git a/TraccarClient/Images.xcassets/alertIcon.imageset/Contents.json b/TraccarClient/Images.xcassets/alertIcon.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..25f5ceb50729746b94532fdb1340749e3f64c47b --- /dev/null +++ b/TraccarClient/Images.xcassets/alertIcon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "undraw_alert_re_j2op 11x.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "undraw_alert_re_j2op 12x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "undraw_alert_re_j2op 13x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 11x.png b/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 11x.png new file mode 100644 index 0000000000000000000000000000000000000000..bac6dd84e2132de700b2341b77330316bda23823 Binary files /dev/null and b/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 11x.png differ diff --git a/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 12x.png b/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 12x.png new file mode 100644 index 0000000000000000000000000000000000000000..a146ecf7447e57e0d47c309a05bb5cf4d9664e90 Binary files /dev/null and b/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 12x.png differ diff --git a/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 13x.png b/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 13x.png new file mode 100644 index 0000000000000000000000000000000000000000..eb22a1390ac03d81a9972440981d8e5de5d1e95c Binary files /dev/null and b/TraccarClient/Images.xcassets/alertIcon.imageset/undraw_alert_re_j2op 13x.png differ diff --git a/TraccarClient/InitialViewController/Controller/InitialViewController.swift b/TraccarClient/InitialViewController/Controller/InitialViewController.swift index 462c4e50d963818e3828d90053a01de2716cf879..80a094a3122e3275ab257521e178ec4beb881d1d 100644 --- a/TraccarClient/InitialViewController/Controller/InitialViewController.swift +++ b/TraccarClient/InitialViewController/Controller/InitialViewController.swift @@ -66,12 +66,10 @@ final class InitialViewController: KNViewController { } func checkShiftStatus(startsAt: String, endsAt: String) -> shiftStatus { - if userDefaults.bool(forKey: Keys.User.autoTracking) == true { + if userDefaults.bool(forKey: Keys.User.autoTracking) == false && shift?.isHourly == false { 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.") @@ -117,7 +115,17 @@ final class InitialViewController: KNViewController { switch shiftStatus { case .failed: print("time formate error") - case .notStart, .inProgress, .end, .none: + case .inProgress: + let alert = AlertViewController() + alert.shift = shift + alert.shiftStatus = shiftStatus + let navigation = KNNavigationController(rootViewController: alert) + navigation.modalPresentationStyle = .overFullScreen + + window?.rootViewController = navigation + window?.makeKeyAndVisible() + + case .notStart, .end, .none: let connect = ConnectViewController() connect.shift = shift connect.shiftStatus = shiftStatus diff --git a/TraccarClient/MainViewController/ConnectViewController.swift b/TraccarClient/MainViewController/ConnectViewController.swift index 3b0e22fd3ab25baf647e45f523716ec47623a28b..2bb89b5269cd4336c53fde64b7eabd6bc7e68605 100644 --- a/TraccarClient/MainViewController/ConnectViewController.swift +++ b/TraccarClient/MainViewController/ConnectViewController.swift @@ -88,14 +88,17 @@ final class ConnectViewController: KNViewController { } private func setupShiftView() { - switch shiftStatus { case .notStart: trackingView.isHidden = true shiftsView.isHidden = false - shiftsView.set(model: shift ?? ShiftModel()) + shiftsView.set(model: shift ?? ShiftModel(), delegate: self) case .inProgress: + trackingView.isHidden = false + shiftsView.isHidden = true + setupTrackingView() + startTimer() userDefaults.set(true, forKey: "service_status_preference") statusChanged(to: true) @@ -106,68 +109,19 @@ final class ConnectViewController: KNViewController { case .end: trackingView.isHidden = true shiftsView.isHidden = false - shiftsView.set(model: shift ?? ShiftModel()) + shiftsView.set(model: shift ?? ShiftModel(), delegate: self) 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() { - trackingView.set(model: shift ?? ShiftModel()) + trackingView.set(model: shift ?? ShiftModel(), delegate: self) } override func viewWillAppear(_ animated: Bool) { @@ -268,3 +222,33 @@ extension ConnectViewController: CustomHeaderViewDelegate { self.navigationController?.pushViewController(settings, animated: true) } } + +extension ConnectViewController: TrackingViewDelegate { + func endtime() { + endTimer() + userDefaults.set(false, forKey: "service_status_preference") + statusChanged(to: false) + TransactionsViewController.addMessage(NSLocalizedString("Service destroyed", comment: "")) + AppDelegate.instance.trackingController?.stop() + AppDelegate.instance.trackingController = nil + + trackingView.isHidden = true + shiftsView.isHidden = false + shiftsView.set(model: shift ?? ShiftModel(), delegate: self) + } +} + +extension ConnectViewController: ShiftViewDelegate { + func startTime() { + startTimer() + userDefaults.set(true, forKey: "service_status_preference") + statusChanged(to: true) + TransactionsViewController.addMessage(NSLocalizedString("Service created", comment: "")) + AppDelegate.instance.trackingController = TrackingController() + AppDelegate.instance.trackingController?.start() + + trackingView.isHidden = false + shiftsView.isHidden = true + setupTrackingView() + } +} diff --git a/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.swift b/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.swift index 895c8ed8e39f4d368bc32c52cb4b4e9ef60a1748..57cddec56b3c0bd7bfaf8df69599b28536afc7fa 100644 --- a/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.swift +++ b/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.swift @@ -7,6 +7,9 @@ // import UIKit +protocol ShiftViewDelegate { + func startTime() +} final class ShiftsView: KNComponentView { // MARK: - Outlets @@ -37,7 +40,9 @@ final class ShiftsView: KNComponentView { private var days: [UILabel] = [] var timer: Timer? var remainingTime: TimeInterval = 0 - + var remainingToEnd: TimeInterval = 0 + var delegate: ShiftViewDelegate? + // MARK: - Lifecycle override func setupNib() { super.setupNib() @@ -96,7 +101,28 @@ final class ShiftsView: KNComponentView { } else { timer?.invalidate() - timeRemaining.text = "Reached 17:00 PM" + + delegate?.startTime() +// let dateFormatter = DateFormatter() +// dateFormatter.dateFormat = "HH:mm" +// +// var currentTime = Date() +// let time = dateFormatter.string(from: Date()) +// if let current = dateFormatter.date(from: time) { +// currentTime = current +// } +// +// let targetTime = dateFormatter.date(from: shiftModel.timings[0].endsAt)! +// +// remainingToEnd = targetTime.timeIntervalSince(currentTime) +// +// if remainingToEnd > 0 { +// timer?.invalidate() +// delegate?.startTime() +// } +// else { +// self.startTimer(model: shiftModel) +// } } } @@ -122,15 +148,20 @@ final class ShiftsView: KNComponentView { private func startTimer(model: ShiftModel) { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "HH:mm" - + var currentTime = Date() let time = dateFormatter.string(from: Date()) if let current = dateFormatter.date(from: time) { currentTime = current } - - let targetTime = dateFormatter.date(from: model.timings[0].startsAt)! - + + var targetTime = dateFormatter.date(from: model.timings[0].startsAt)! + + // if targetTime is earlier than currentTime, add 1 day to targetTime + if targetTime < currentTime { + targetTime = Calendar.current.date(byAdding: .day, value: 1, to: targetTime)! + } + remainingTime = targetTime.timeIntervalSince(currentTime) timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(updateTimeLabel), userInfo: nil, repeats: true) @@ -138,7 +169,8 @@ final class ShiftsView: KNComponentView { timer?.fire() } - func set(model: ShiftModel) { + func set(model: ShiftModel, delegate: ShiftViewDelegate) { + self.delegate = delegate self.shiftModel = model setShiftDays(daysId: model.timings[0].daysOfWeek) diff --git a/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.swift b/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.swift index dd823e811c5a8bd26f48f6a1198c2a2ac18b69de..83ad8dcceba5df9707536b68560a41be10cd9913 100644 --- a/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.swift +++ b/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.swift @@ -7,6 +7,9 @@ // import UIKit +protocol TrackingViewDelegate { + func endtime() +} final class TrackingView: KNComponentView { // MARK: - Outlets @@ -31,7 +34,7 @@ final class TrackingView: KNComponentView { var timer: Timer! let timeFormat = "HH:mm" let interval = 60.0 // 1 minute - + var delegate: TrackingViewDelegate? // MARK: - Lifecycle override func setupNib() { @@ -76,12 +79,13 @@ final class TrackingView: KNComponentView { endShiftLable.set(text: "Shift Ends", color: .invalid, font: .regular(11)) -// workingTimeLable.set(text: "Working Time: 03:24", color: .black, font: .medium(10)) + // workingTimeLable.set(text: "Working Time: 03:24", color: .black, font: .medium(10)) workingTimeLable.set(text: "", color: .black, font: .medium(10)) - + } - func set(model: ShiftModel) { + func set(model: ShiftModel, delegate: TrackingViewDelegate) { + self.delegate = delegate shift = model configureSlider(model: model) setupTimer() @@ -104,13 +108,68 @@ final class TrackingView: KNComponentView { timeSlider.minimumValue = 0 timeSlider.maximumValue = Float(endDate.timeIntervalSince(startDate) / interval) - timeSlider.value = 0 + + let now = Date() + print("now: \(now)") + + let calendar = Calendar.current + let nowComponents = calendar.dateComponents([.year, .month, .day], from: now) + + var start: Date = currentTime + var end: Date = endTimeDate + + var startComponents = calendar.dateComponents([.hour, .minute, .second], from: startDate) + startComponents.year = nowComponents.year + startComponents.month = nowComponents.month + startComponents.day = nowComponents.day + start = calendar.date(from: startComponents)! + + var endComponents = calendar.dateComponents([.hour, .minute, .second], from: endDate) + endComponents.year = nowComponents.year + endComponents.month = nowComponents.month + endComponents.day = nowComponents.day + end = calendar.date(from: endComponents)! + + if let endDate = Calendar.current.date(from: endComponents) { + timeLeftLabel.text = calculateRemainingTime(endDate: endDate) + } + + if now >= start && now <= end { + timeSlider.value = Float(now.timeIntervalSince(start) / interval) + } else { + timeSlider.value = 0 + } } func setupTimer() { timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(updateSlider), userInfo: nil, repeats: true) } + // @objc func updateSlider() { + // timeSlider.value += 1 + // + // guard let currentValue = currentTime else { + // return + // } + // + // let updatedTime = currentValue.addingTimeInterval(interval) + // + // if updatedTime <= endTimeDate { + // currentTime = updatedTime + // + // let dateFormatter = DateFormatter() + // dateFormatter.dateFormat = timeFormat + // + // let timeString = dateFormatter.string(from: updatedTime) + // print(timeString) // You can use this time string as per your requirement + // + // } else { + // timer.invalidate() + // delegate?.endtime() + // + // } + // } + @objc func updateSlider() { timeSlider.value += 1 @@ -120,7 +179,18 @@ final class TrackingView: KNComponentView { let updatedTime = currentValue.addingTimeInterval(interval) - if updatedTime <= endTimeDate { + let calendar = Calendar.current + var endComponents = calendar.dateComponents([.hour, .minute, .second], from: endTimeDate) + endComponents.year = calendar.component(.year, from: updatedTime) + endComponents.month = calendar.component(.month, from: updatedTime) + endComponents.day = calendar.component(.day, from: updatedTime) + if currentTime > endTimeDate { + // If start time is later than end time, the shift ends the next day + endComponents.day = calendar.component(.day, from: updatedTime) + 1 + } + let adjustedEndTimeDate = calendar.date(from: endComponents)! + + if updatedTime <= adjustedEndTimeDate { currentTime = updatedTime let dateFormatter = DateFormatter() @@ -129,8 +199,41 @@ final class TrackingView: KNComponentView { let timeString = dateFormatter.string(from: updatedTime) print(timeString) // You can use this time string as per your requirement + let now = Date() + let calendar = Calendar.current + let nowComponents = calendar.dateComponents([.year, .month, .day], from: now) + + var end: Date = endTimeDate + + guard let endDate = dateFormatter.date(from: shift?.timings[0].endsAt ?? "") else { + return + } + var endComponents = calendar.dateComponents([.hour, .minute, .second], from: endDate) + endComponents.year = nowComponents.year + endComponents.month = nowComponents.month + endComponents.day = nowComponents.day + end = calendar.date(from: endComponents)! + + if let endDate = Calendar.current.date(from: endComponents) { + if calculateRemainingTime(endDate: endDate) != "Time's up!" { + timeLeftLabel.text = calculateRemainingTime(endDate: endDate) + } else { + timer.invalidate() + delegate?.endtime() + } + } + } + } + + func calculateRemainingTime(endDate: Date) -> String { + let remainingTimeInSeconds = endDate.timeIntervalSinceNow + if remainingTimeInSeconds > 0 { + let formatter = DateComponentsFormatter() + formatter.allowedUnits = [.hour, .minute] + formatter.unitsStyle = .full + return formatter.string(from: TimeInterval(remainingTimeInSeconds)) ?? "Time's up!" } else { - timer.invalidate() + return "Time's up!" } } } diff --git a/TraccarClient/UIImage.swift b/TraccarClient/UIImage.swift index df7495edb0568839be00a055679f30e018010b27..1a9fe31ea382d8141f4b80acce111ae785a9cd52 100644 --- a/TraccarClient/UIImage.swift +++ b/TraccarClient/UIImage.swift @@ -28,6 +28,7 @@ extension UIImage { static let logout = img("logout") static let handle = img("handle") static let privacy = img("privacyPolicy") + static let alertIcon = img("alertIcon") } func img(_ name: String) -> UIImage {