diff --git a/.DS_Store b/.DS_Store index af7c5950eb1216049b34e074baedcb84f6dda4dd..c42df0bc1e5c61d76375f7e14efdbe400b1347eb 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/TraccarClient.xcodeproj/project.pbxproj b/TraccarClient.xcodeproj/project.pbxproj index 2964b519786b0c3678771df28520051e0dbee82d..66743bc405ab636d065a34a06a5686d2f15864b1 100644 --- a/TraccarClient.xcodeproj/project.pbxproj +++ b/TraccarClient.xcodeproj/project.pbxproj @@ -92,6 +92,8 @@ 532683C12AEA50FA00A364C0 /* LoginViewControllerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 532683C02AEA50FA00A364C0 /* LoginViewControllerProtocol.swift */; }; 532683C32AEA537F00A364C0 /* UITableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 532683C22AEA537F00A364C0 /* UITableView.swift */; }; 532683C82AEA631800A364C0 /* IQKeyboardManagerSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 532683C72AEA631800A364C0 /* IQKeyboardManagerSwift */; }; + 53295BEE2B09FBA200DB9163 /* ShiftsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53295BED2B09FBA200DB9163 /* ShiftsView.swift */; }; + 53295BF02B09FBAC00DB9163 /* ShiftsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53295BEF2B09FBAC00DB9163 /* ShiftsView.xib */; }; 532FDC1B2B00BED500EDFC99 /* Network+Shifts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 532FDC1A2B00BED500EDFC99 /* Network+Shifts.swift */; }; 53554ADF2AED1B480018BAEE /* KNButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53554AD92AED1B480018BAEE /* KNButtonView.swift */; }; 53554AE02AED1B480018BAEE /* KNButtonViewHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53554ADA2AED1B480018BAEE /* KNButtonViewHelper.swift */; }; @@ -102,6 +104,8 @@ 5370B4702AEFB8A900AE08CC /* splash.json in Resources */ = {isa = PBXBuildFile; fileRef = 5370B46F2AEFB8A900AE08CC /* splash.json */; }; 5392C4232B037942004EF18A /* ShiftsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5392C4222B037942004EF18A /* ShiftsModel.swift */; }; 5392C4252B04A760004EF18A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5392C4242B04A760004EF18A /* GoogleService-Info.plist */; }; + 53A306212B0CA92900FAEA00 /* TrackingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53A306202B0CA92900FAEA00 /* TrackingView.swift */; }; + 53A306232B0CAF7800FAEA00 /* TrackingView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 53A306222B0CAF7800FAEA00 /* TrackingView.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 */; }; @@ -264,6 +268,8 @@ 532683BE2AEA50EF00A364C0 /* LoginDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginDataProvider.swift; sourceTree = "<group>"; }; 532683C02AEA50FA00A364C0 /* LoginViewControllerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewControllerProtocol.swift; sourceTree = "<group>"; }; 532683C22AEA537F00A364C0 /* UITableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableView.swift; sourceTree = "<group>"; }; + 53295BED2B09FBA200DB9163 /* ShiftsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShiftsView.swift; sourceTree = "<group>"; }; + 53295BEF2B09FBAC00DB9163 /* ShiftsView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShiftsView.xib; sourceTree = "<group>"; }; 532FDC1A2B00BED500EDFC99 /* Network+Shifts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Network+Shifts.swift"; sourceTree = "<group>"; }; 53554AD92AED1B480018BAEE /* KNButtonView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KNButtonView.swift; sourceTree = "<group>"; }; 53554ADA2AED1B480018BAEE /* KNButtonViewHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KNButtonViewHelper.swift; sourceTree = "<group>"; }; @@ -274,6 +280,8 @@ 5370B46F2AEFB8A900AE08CC /* splash.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = splash.json; sourceTree = "<group>"; }; 5392C4222B037942004EF18A /* ShiftsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShiftsModel.swift; sourceTree = "<group>"; }; 5392C4242B04A760004EF18A /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; }; + 53A306202B0CA92900FAEA00 /* TrackingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackingView.swift; sourceTree = "<group>"; }; + 53A306222B0CAF7800FAEA00 /* TrackingView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TrackingView.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>"; }; @@ -649,6 +657,15 @@ path = Custom; sourceTree = "<group>"; }; + 53295BEC2B09FB8200DB9163 /* CustomViews */ = { + isa = PBXGroup; + children = ( + 53A3061F2B0CA87900FAEA00 /* TrackingView */, + 53A3061E2B0CA86D00FAEA00 /* ShiftsView */, + ); + path = CustomViews; + sourceTree = "<group>"; + }; 53554AD82AED1B480018BAEE /* KNButtonView */ = { isa = PBXGroup; children = ( @@ -669,6 +686,24 @@ path = Cell; sourceTree = "<group>"; }; + 53A3061E2B0CA86D00FAEA00 /* ShiftsView */ = { + isa = PBXGroup; + children = ( + 53295BED2B09FBA200DB9163 /* ShiftsView.swift */, + 53295BEF2B09FBAC00DB9163 /* ShiftsView.xib */, + ); + path = ShiftsView; + sourceTree = "<group>"; + }; + 53A3061F2B0CA87900FAEA00 /* TrackingView */ = { + isa = PBXGroup; + children = ( + 53A306202B0CA92900FAEA00 /* TrackingView.swift */, + 53A306222B0CAF7800FAEA00 /* TrackingView.xib */, + ); + path = TrackingView; + sourceTree = "<group>"; + }; 53D62E3C2AEFA2F800C80BAC /* InitialViewController */ = { isa = PBXGroup; children = ( @@ -728,6 +763,7 @@ 53F10AF12AF0F267004D0529 /* MainViewController */ = { isa = PBXGroup; children = ( + 53295BEC2B09FB8200DB9163 /* CustomViews */, CBAA0F7E1F68E807008BBBBE /* MainViewController.swift */, 53F10AF22AF0F306004D0529 /* ConnectViewController.swift */, 53F10AF32AF0F306004D0529 /* ConnectViewController.xib */, @@ -968,6 +1004,7 @@ 5326835F2AE91A6F00A364C0 /* Montserrat-Black.ttf in Resources */, 53EBC5FF2AF199FF00601AA7 /* SettingsTextTableViewCell.xib in Resources */, 532683742AE923A500A364C0 /* KNTextFieldView.xib in Resources */, + 53295BF02B09FBAC00DB9163 /* ShiftsView.xib in Resources */, 532683622AE91A6F00A364C0 /* Montserrat-ExtraBoldItalic.ttf in Resources */, 5326835E2AE91A6F00A364C0 /* Montserrat-Regular.ttf in Resources */, 532683522AE91A6F00A364C0 /* Montserrat-Light.ttf in Resources */, @@ -997,6 +1034,7 @@ 532683512AE91A6F00A364C0 /* Montserrat-ExtraLightItalic.ttf in Resources */, 530080392AF15CE000A05E04 /* TransactionsViewController.xib in Resources */, 5392C4252B04A760004EF18A /* GoogleService-Info.plist in Resources */, + 53A306232B0CAF7800FAEA00 /* TrackingView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1078,6 +1116,7 @@ 532683872AE9295500A364C0 /* Nameable.swift in Sources */, 5326837E2AE923A500A364C0 /* KNFieldDropdownObjectProtocol.swift in Sources */, 53F10AEA2AF0602C004D0529 /* UINavigationController.swift in Sources */, + 53A306212B0CA92900FAEA00 /* TrackingView.swift in Sources */, 532683752AE923A500A364C0 /* KNTextFieldView+Protocols.swift in Sources */, 532683A52AE94A3500A364C0 /* KNTextField.swift in Sources */, 53157EDA2AEE57FA003C9B6A /* UITextView.swift in Sources */, @@ -1091,6 +1130,7 @@ CBCE82F21B8D265800A7318B /* TraccarClient.xcdatamodeld in Sources */, 532683762AE923A500A364C0 /* KNTextFieldViewHelper.swift in Sources */, 53FFDB9B2AF8FD1D0071F396 /* API+Permissions.swift in Sources */, + 53295BEE2B09FBA200DB9163 /* ShiftsView.swift in Sources */, 53F10AEC2AF06556004D0529 /* UIImage.swift in Sources */, 532683A72AE94ADC00A364C0 /* KNObject.swift in Sources */, 532683A12AE948FF00A364C0 /* AppManager.swift in Sources */, 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 13f4b4488327543b9bf9fcccddc068240586c86a..bf9388a6fc806ff6e8a7f858a0227a2d4d355d5d 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/Color.swift b/TraccarClient/Color.swift index 3b32b625b3b261096db8856a7e6a12595a5f3102..19700dca2afe4c38043fa3a4775fb2a0929891a0 100644 --- a/TraccarClient/Color.swift +++ b/TraccarClient/Color.swift @@ -12,4 +12,7 @@ import UIKit extension UIColor { static let main = hex("#62389F") + static let secondary = hex("#7367F0") + static let invalid = hex("#4B465C").withAlphaComponent(0.16) + static let invalidText = hex("#4B465C") } diff --git a/TraccarClient/Images.xcassets/.DS_Store b/TraccarClient/Images.xcassets/.DS_Store index b7f788c837f88ef2cf6586e8cb95f602abadb157..2b2316d0cc348455109f9a248d84c58f01ba5144 100644 Binary files a/TraccarClient/Images.xcassets/.DS_Store and b/TraccarClient/Images.xcassets/.DS_Store differ diff --git a/TraccarClient/Images.xcassets/handle.imageset/Contents.json b/TraccarClient/Images.xcassets/handle.imageset/Contents.json new file mode 100644 index 0000000000000000000000000000000000000000..8658fc6020c58a7f654025a59d5fde7e982f2436 --- /dev/null +++ b/TraccarClient/Images.xcassets/handle.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "Handle1x.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Handle2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Handle3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TraccarClient/Images.xcassets/handle.imageset/Handle1x.png b/TraccarClient/Images.xcassets/handle.imageset/Handle1x.png new file mode 100644 index 0000000000000000000000000000000000000000..2e2736b121c51013f17d36203bbd107b0239cd28 Binary files /dev/null and b/TraccarClient/Images.xcassets/handle.imageset/Handle1x.png differ diff --git a/TraccarClient/Images.xcassets/handle.imageset/Handle2x.png b/TraccarClient/Images.xcassets/handle.imageset/Handle2x.png new file mode 100644 index 0000000000000000000000000000000000000000..37dadf0e9b9d89f29362a2fd852f734701b9bedf Binary files /dev/null and b/TraccarClient/Images.xcassets/handle.imageset/Handle2x.png differ diff --git a/TraccarClient/Images.xcassets/handle.imageset/Handle3x.png b/TraccarClient/Images.xcassets/handle.imageset/Handle3x.png new file mode 100644 index 0000000000000000000000000000000000000000..0a438ef17ae2d41cc56a6cdd747da99b059a4ba5 Binary files /dev/null and b/TraccarClient/Images.xcassets/handle.imageset/Handle3x.png differ diff --git a/TraccarClient/MainViewController/ConnectViewController.swift b/TraccarClient/MainViewController/ConnectViewController.swift index 1ad57f43c75d61c072dd92415e516635dcfdcf23..d432faad23b2fc4555751a50c5809d61ea6d76ec 100644 --- a/TraccarClient/MainViewController/ConnectViewController.swift +++ b/TraccarClient/MainViewController/ConnectViewController.swift @@ -17,17 +17,21 @@ final class ConnectViewController: KNViewController { @IBOutlet private weak var discLabel: UILabel! @IBOutlet private weak var statusLabel: UILabel! @IBOutlet private weak var timerLabel: UILabel! + @IBOutlet private weak var shiftsView: ShiftsView! + @IBOutlet private weak var trackingView: TrackingView! // MARK: - Properties let userDefaults = UserDefaults.standard var trackingController: TrackingController? private lazy var totalTime = 0 - + private var timer: Timer? private var isInBackground: Bool = false private var currentBackgroundDate = Date() let status: Bool = false var shift: ShiftModel? + let timeFormat = "HH:mm" + let dateFormatter = DateFormatter() // MARK: - LifeCycle override func viewDidLoad() { @@ -41,6 +45,7 @@ final class ConnectViewController: KNViewController { } private func setupUI() { + setupShiftView() customHeaderView.set(type: .home, delegate: self) timerLabel.text = "" connectButton.set(title: "") @@ -56,6 +61,60 @@ final class ConnectViewController: KNViewController { } + private func setupShiftView() { + if userDefaults.bool(forKey: Keys.User.autoTracking) == false { + 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()) + } + override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) hasCustomNavigation = true @@ -146,7 +205,7 @@ extension ConnectViewController: CustomHeaderViewDelegate { func rightButtonTapped(action: RightButtonAction) { let transactions = TransactionsViewController() self.navigationController?.pushViewController(transactions, animated: true) - + } func leftButtonTapped(action: LeftButtonAction) { diff --git a/TraccarClient/MainViewController/ConnectViewController.xib b/TraccarClient/MainViewController/ConnectViewController.xib index 19377aa64b8af3d6fdbf3f5075a14436b4d45115..66f1541c5c96eeee06df63a852e771e639badf21 100644 --- a/TraccarClient/MainViewController/ConnectViewController.xib +++ b/TraccarClient/MainViewController/ConnectViewController.xib @@ -15,8 +15,10 @@ <outlet property="connectionStatusLogo" destination="zub-LG-NJa" id="WSa-Cl-2dv"/> <outlet property="customHeaderView" destination="sRb-Ee-0gO" id="9Wm-RW-Xoy"/> <outlet property="discLabel" destination="GMM-3p-jRe" id="4fG-9o-848"/> + <outlet property="shiftsView" destination="yBt-VZ-plB" id="dft-f0-wg7"/> <outlet property="statusLabel" destination="3f0-IX-LtZ" id="2fh-ed-xJp"/> <outlet property="timerLabel" destination="tx9-o4-hgS" id="p5k-Iq-GJH"/> + <outlet property="trackingView" destination="o03-9b-10U" id="XOo-zp-Vqv"/> <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/> </connections> </placeholder> @@ -82,26 +84,43 @@ <constraint firstAttribute="height" constant="95" id="9ID-fz-tzv"/> </constraints> </view> + <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="yBt-VZ-plB" customClass="ShiftsView" customModule="TraccarClient" customModuleProvider="target"> + <rect key="frame" x="0.0" y="528" width="393" height="301"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + </view> + <view hidden="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="o03-9b-10U" customClass="TrackingView" customModule="TraccarClient" customModuleProvider="target"> + <rect key="frame" x="0.0" y="528" width="393" height="301"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + </view> </subviews> <viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/> <color key="backgroundColor" systemColor="systemBackgroundColor"/> <constraints> <constraint firstItem="3f0-IX-LtZ" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="2ff-id-KKY"/> <constraint firstItem="zub-LG-NJa" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="4fj-2R-IeS"/> + <constraint firstItem="yBt-VZ-plB" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="7vT-Vo-QW1"/> <constraint firstItem="tx9-o4-hgS" firstAttribute="top" secondItem="3f0-IX-LtZ" secondAttribute="bottom" constant="10" id="B0j-M3-qoh"/> <constraint firstItem="GMM-3p-jRe" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="ClB-52-WWZ"/> + <constraint firstItem="o03-9b-10U" firstAttribute="top" secondItem="zub-LG-NJa" secondAttribute="bottom" constant="20" id="Gc3-WA-mir"/> <constraint firstItem="nK6-XO-h2t" firstAttribute="top" secondItem="sRb-Ee-0gO" secondAttribute="bottom" id="JPj-zS-Bze"/> <constraint firstItem="nK6-XO-h2t" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="LZN-ga-CaE"/> <constraint firstItem="GMM-3p-jRe" firstAttribute="trailing" secondItem="zub-LG-NJa" secondAttribute="trailing" id="MmD-WW-7cj"/> <constraint firstItem="GMM-3p-jRe" firstAttribute="top" secondItem="zub-LG-NJa" secondAttribute="bottom" constant="20" id="QJn-Ap-lcV"/> + <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="o03-9b-10U" secondAttribute="bottom" constant="10" id="RXf-jb-yme"/> <constraint firstItem="CkC-Ms-GkO" firstAttribute="top" secondItem="GMM-3p-jRe" secondAttribute="bottom" constant="20" id="S7D-8h-M4g"/> <constraint firstItem="GMM-3p-jRe" firstAttribute="leading" secondItem="zub-LG-NJa" secondAttribute="leading" id="XEg-qX-IP0"/> <constraint firstItem="CkC-Ms-GkO" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="Yfb-ej-e93"/> <constraint firstItem="sRb-Ee-0gO" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="ZkK-Y2-fnp"/> <constraint firstItem="tx9-o4-hgS" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="bBV-Q8-eeY"/> + <constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="yBt-VZ-plB" secondAttribute="trailing" id="bf7-YF-Pu1"/> <constraint firstItem="zub-LG-NJa" firstAttribute="top" secondItem="nK6-XO-h2t" secondAttribute="bottom" constant="10" id="fQE-Oi-c8X"/> + <constraint firstAttribute="trailing" secondItem="o03-9b-10U" secondAttribute="trailing" id="hGz-dF-Cdm"/> <constraint firstItem="sRb-Ee-0gO" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="qJD-v2-eXk"/> + <constraint firstItem="yBt-VZ-plB" firstAttribute="top" secondItem="zub-LG-NJa" secondAttribute="bottom" constant="20" id="qeH-6k-KSO"/> <constraint firstItem="3f0-IX-LtZ" firstAttribute="top" secondItem="CkC-Ms-GkO" secondAttribute="bottom" constant="20" id="spU-lY-vSm"/> + <constraint firstItem="o03-9b-10U" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="tdo-is-GJH"/> + <constraint firstItem="yBt-VZ-plB" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="wgL-Do-yup"/> + <constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="yBt-VZ-plB" secondAttribute="bottom" constant="10" id="ws2-d6-hl0"/> <constraint firstItem="sRb-Ee-0gO" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="yiC-Qw-Eb9"/> </constraints> <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> diff --git a/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.swift b/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.swift new file mode 100644 index 0000000000000000000000000000000000000000..895c8ed8e39f4d368bc32c52cb4b4e9ef60a1748 --- /dev/null +++ b/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.swift @@ -0,0 +1,153 @@ +// +// ShiftsView.swift +// TraccarClient +// +// Created by George Makhoul on 19/11/2023. +// Copyright © 2023 Traccar. All rights reserved. +// + +import UIKit + +final class ShiftsView: KNComponentView { + // MARK: - Outlets + @IBOutlet var view: UIView! + @IBOutlet private weak var connectionStatusLabel: UILabel! + @IBOutlet private weak var descLabel1: UILabel! + @IBOutlet private weak var descLabel2: UILabel! + @IBOutlet private weak var timeRemaining: UILabel! + + @IBOutlet private weak var workingDaysLabel: UILabel! + @IBOutlet private weak var daysStack: UIStackView! + @IBOutlet private weak var startLabel: UILabel! + @IBOutlet private weak var endLabel: UILabel! + @IBOutlet private weak var startTimeLabel: UILabel! + @IBOutlet private weak var endTimeLabel: UILabel! + @IBOutlet private weak var startTimeView: UIView! + @IBOutlet private weak var endTimeView: UIView! + @IBOutlet private weak var sundayLabel: UILabel! + @IBOutlet private weak var mondayLabel: UILabel! + @IBOutlet private weak var tuesdayLabel: UILabel! + @IBOutlet private weak var wednesdayLabel: UILabel! + @IBOutlet private weak var thursdayLabel: UILabel! + @IBOutlet private weak var fridayLabel: UILabel! + @IBOutlet private weak var saturdayLabel: UILabel! + + // MARK: - Properties + private var shiftModel = ShiftModel() + private var days: [UILabel] = [] + var timer: Timer? + var remainingTime: TimeInterval = 0 + + // MARK: - Lifecycle + override func setupNib() { + super.setupNib() + + view.frame = bounds + view.autoresizingMask = [.flexibleHeight, .flexibleWidth] + + setupUI() + } + + private func setupUI() { + + days = [sundayLabel, mondayLabel, tuesdayLabel, wednesdayLabel, thursdayLabel, fridayLabel, saturdayLabel] + + initDays(days: days) + + connectionStatusLabel.set(text: "Tracking stopped.", color: .black, font: .bold(20)) + connectionStatusLabel.textAlignment = .center + + descLabel1.set(text: "Tracking will start after", color: .black, font: .regular(16)) + descLabel1.textAlignment = .center + + timeRemaining.set(text: "2 hours 46 minutes", color: .black, font: .bold(16)) + timeRemaining.textAlignment = .center + + descLabel2.set(text: "at the beginning of your shift", color: .black, font: .regular(16)) + descLabel2.textAlignment = .center + + workingDaysLabel.set(text: "Working Days", color: .black, font: .medium(20)) + workingDaysLabel.textAlignment = .center + + daysStack.distribution = .fillEqually + daysStack.spacing = 10 + + startLabel.set(text: "Shift Starts at", color: .black, font: .medium(18)) + endLabel.set(text: "Shift Ends at", color: .black, font: .medium(18)) + + startTimeView.addCorners(4) + endTimeView.addCorners(4) + + startTimeView.backgroundColor = .invalid + endTimeView.backgroundColor = .invalid + + startTimeLabel.set(text: "", color: .invalidText, font: .semibold(13)) + endTimeLabel.set(text: "", color: .invalidText, font: .semibold(13)) + } + + @objc func updateTimeLabel() { + if remainingTime > 0 { + let hours = Int(remainingTime) / 3600 + let minutes = (Int(remainingTime) % 3600) / 60 + + timeRemaining.text = "\(hours) hours \(minutes) minutes" + + remainingTime -= 60 // Subtract 60 seconds (1 minute) + + } else { + timer?.invalidate() + timeRemaining.text = "Reached 17:00 PM" + } + } + + private func initDays(days: [UILabel]) { + for day in days { + day.addCorners(4) + day.set(color: .invalidText) + day.backgroundColor = .invalid + } + } + + private func setShiftDays(daysId: [String]) { + for day in days { + for id in daysId { + if day.restorationIdentifier == id { + day.set(color: .white) + day.backgroundColor = .secondary + } + } + } + } + + 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)! + + remainingTime = targetTime.timeIntervalSince(currentTime) + + timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(updateTimeLabel), userInfo: nil, repeats: true) + RunLoop.current.add(timer!, forMode: RunLoop.Mode.common) + timer?.fire() + } + + func set(model: ShiftModel) { + self.shiftModel = model + setShiftDays(daysId: model.timings[0].daysOfWeek) + + startTimeLabel.set(text: model.timings[0].startsAt) + startTimeLabel.textAlignment = .center + + endTimeLabel.set(text: model.timings[0].endsAt) + endTimeLabel.textAlignment = .center + + startTimer(model: model) + } +} diff --git a/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.xib b/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.xib new file mode 100644 index 0000000000000000000000000000000000000000..c384068fe8a1aff6c7d7f4086be7e577e87bdfb2 --- /dev/null +++ b/TraccarClient/MainViewController/CustomViews/ShiftsView/ShiftsView.xib @@ -0,0 +1,257 @@ +<?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_12" 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> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ShiftsView" customModule="TraccarClient" customModuleProvider="target"> + <connections> + <outlet property="connectionStatusLabel" destination="PDJ-dE-Eam" id="sMd-Ex-i2d"/> + <outlet property="daysStack" destination="zkz-CT-krb" id="mXc-nU-Fch"/> + <outlet property="descLabel1" destination="cxv-Rj-jyZ" id="Sv5-d8-K84"/> + <outlet property="descLabel2" destination="gvg-Dw-ZgB" id="qn5-dg-ngv"/> + <outlet property="endLabel" destination="Jn5-Yz-JFE" id="5nv-x8-sTT"/> + <outlet property="endTimeLabel" destination="gVU-Ow-ZZ1" id="V12-PZ-8Eg"/> + <outlet property="endTimeView" destination="3En-Qt-cec" id="sJh-kA-cmE"/> + <outlet property="fridayLabel" destination="1z3-YS-wKP" id="20Q-lW-DH7"/> + <outlet property="mondayLabel" destination="kmL-nQ-50h" id="j97-c6-diF"/> + <outlet property="saturdayLabel" destination="v1N-k1-2ED" id="JQb-b4-OZc"/> + <outlet property="startLabel" destination="1jP-g6-5ve" id="2fw-zw-mVj"/> + <outlet property="startTimeLabel" destination="kfK-lP-2ey" id="N4e-BM-66v"/> + <outlet property="startTimeView" destination="fKD-vo-qus" id="2zx-y4-xkO"/> + <outlet property="sundayLabel" destination="U8p-VB-3J4" id="eWK-J5-ueh"/> + <outlet property="thursdayLabel" destination="sUk-PX-pYr" id="XqJ-ja-4eE"/> + <outlet property="timeRemaining" destination="zed-bF-ruL" id="DCm-r3-Yeq"/> + <outlet property="tuesdayLabel" destination="CHf-5s-cu5" id="28N-K1-ibL"/> + <outlet property="view" destination="iN0-l3-epB" id="8YO-Zg-e9G"/> + <outlet property="wednesdayLabel" destination="bh9-IG-I4y" id="REb-p6-EAT"/> + <outlet property="workingDaysLabel" destination="Mtn-Bf-Lzt" id="EqR-Fj-7tO"/> + </connections> + </placeholder> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" id="iN0-l3-epB"> + <rect key="frame" x="0.0" y="0.0" width="375" height="354"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tracking stopped." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PDJ-dE-Eam"> + <rect key="frame" x="10" y="0.0" width="355" height="24"/> + <constraints> + <constraint firstAttribute="height" constant="24" id="9rp-Qc-CdU"/> + </constraints> + <fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="20"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" spacing="10" translatesAutoresizingMaskIntoConstraints="NO" id="zkz-CT-krb"> + <rect key="frame" x="10" y="214" width="355" height="22"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" restorationIdentifier="sunday" text="SUN" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="U8p-VB-3J4"> + <rect key="frame" x="0.0" y="0.0" width="42" height="22"/> + <color key="backgroundColor" red="0.45098039215686275" green="0.40392156862745099" blue="0.94117647058823528" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" restorationIdentifier="monday" text="MON" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kmL-nQ-50h"> + <rect key="frame" x="52" y="0.0" width="42.333333333333343" height="22"/> + <color key="backgroundColor" red="0.45098039220000002" green="0.4039215686" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" restorationIdentifier="tuesday" text="TUE" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="CHf-5s-cu5"> + <rect key="frame" x="104.33333333333333" y="0.0" width="41.999999999999986" height="22"/> + <color key="backgroundColor" red="0.45098039220000002" green="0.4039215686" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" restorationIdentifier="wednesday" text="WED" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bh9-IG-I4y"> + <rect key="frame" x="156.33333333333334" y="0.0" width="42.333333333333343" height="22"/> + <color key="backgroundColor" red="0.45098039220000002" green="0.4039215686" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" restorationIdentifier="thursday" text="THU" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sUk-PX-pYr"> + <rect key="frame" x="208.66666666666666" y="0.0" width="42" height="22"/> + <color key="backgroundColor" red="0.45098039220000002" green="0.4039215686" blue="0.94117647059999998" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" restorationIdentifier="friday" text="FRI" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1z3-YS-wKP"> + <rect key="frame" x="260.66666666666669" y="0.0" width="42.333333333333314" height="22"/> + <color key="backgroundColor" red="0.29411764705882354" green="0.27450980392156865" blue="0.36078431372549019" alpha="0.16452814569536423" colorSpace="custom" customColorSpace="sRGB"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" red="0.29411764705882354" green="0.27450980392156865" blue="0.36078431372549019" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" restorationIdentifier="saturday" text="SAT" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="v1N-k1-2ED"> + <rect key="frame" x="313" y="0.0" width="42" height="22"/> + <color key="backgroundColor" red="0.29411764705882354" green="0.27450980392156865" blue="0.36078431372549019" alpha="0.16452814569536423" colorSpace="custom" customColorSpace="sRGB"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" red="0.29411764705882354" green="0.27450980392156865" blue="0.36078431372549019" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <constraints> + <constraint firstAttribute="height" constant="22" id="q6b-Kc-6wU"/> + </constraints> + </stackView> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" spacing="12" translatesAutoresizingMaskIntoConstraints="NO" id="caN-rO-3Wt"> + <rect key="frame" x="87.666666666666686" y="256" width="200" height="60"/> + <subviews> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="cl4-kc-ll5"> + <rect key="frame" x="0.0" y="0.0" width="200" height="24"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Shift Starts at" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1jP-g6-5ve"> + <rect key="frame" x="0.0" y="0.0" width="145" height="24"/> + <fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fKD-vo-qus"> + <rect key="frame" x="145" y="0.0" width="55" height="24"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="09:00" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kfK-lP-2ey"> + <rect key="frame" x="0.0" y="0.0" width="55" height="24"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="0.29411764705882354" green="0.27450980392156865" blue="0.36078431372549019" alpha="0.16" colorSpace="custom" customColorSpace="sRGB"/> + <constraints> + <constraint firstAttribute="trailing" secondItem="kfK-lP-2ey" secondAttribute="trailing" id="4iM-XN-Vea"/> + <constraint firstItem="kfK-lP-2ey" firstAttribute="leading" secondItem="fKD-vo-qus" secondAttribute="leading" id="6cC-tC-YeS"/> + <constraint firstAttribute="bottom" secondItem="kfK-lP-2ey" secondAttribute="bottom" id="FLH-Mj-S32"/> + <constraint firstItem="kfK-lP-2ey" firstAttribute="top" secondItem="fKD-vo-qus" secondAttribute="top" id="NBr-2a-tqp"/> + <constraint firstAttribute="width" constant="55" id="Q4w-aF-fvI"/> + </constraints> + </view> + </subviews> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <constraints> + <constraint firstItem="fKD-vo-qus" firstAttribute="leading" secondItem="1jP-g6-5ve" secondAttribute="trailing" id="1cm-cN-bBp"/> + <constraint firstAttribute="trailing" secondItem="fKD-vo-qus" secondAttribute="trailing" id="3w5-5p-S1Y"/> + <constraint firstAttribute="bottom" secondItem="1jP-g6-5ve" secondAttribute="bottom" id="Kq6-kA-kNZ"/> + <constraint firstItem="1jP-g6-5ve" firstAttribute="top" secondItem="cl4-kc-ll5" secondAttribute="top" id="LRo-1a-3TH"/> + <constraint firstItem="fKD-vo-qus" firstAttribute="top" secondItem="cl4-kc-ll5" secondAttribute="top" id="asB-n3-sgQ"/> + <constraint firstItem="1jP-g6-5ve" firstAttribute="leading" secondItem="cl4-kc-ll5" secondAttribute="leading" id="cAV-4C-qe1"/> + <constraint firstAttribute="bottom" secondItem="fKD-vo-qus" secondAttribute="bottom" id="xik-kG-i4Q"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3re-Oq-Oeh"> + <rect key="frame" x="0.0" y="36" width="200" height="24"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Shift Ends at" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jn5-Yz-JFE"> + <rect key="frame" x="0.0" y="0.0" width="145" height="24"/> + <fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="3En-Qt-cec"> + <rect key="frame" x="145" y="0.0" width="55" height="24"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="17:00" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gVU-Ow-ZZ1"> + <rect key="frame" x="0.0" y="0.0" width="55" height="24"/> + <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="13"/> + <color key="textColor" white="0.33333333329999998" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" red="0.29411764709999999" green="0.27450980390000002" blue="0.36078431370000003" alpha="0.16" colorSpace="custom" customColorSpace="sRGB"/> + <constraints> + <constraint firstItem="gVU-Ow-ZZ1" firstAttribute="leading" secondItem="3En-Qt-cec" secondAttribute="leading" id="PA7-Ol-4as"/> + <constraint firstAttribute="bottom" secondItem="gVU-Ow-ZZ1" secondAttribute="bottom" id="eqC-XB-IJa"/> + <constraint firstAttribute="width" constant="55" id="kMd-Nk-6DD"/> + <constraint firstAttribute="trailing" secondItem="gVU-Ow-ZZ1" secondAttribute="trailing" id="tFq-2K-lZ1"/> + <constraint firstItem="gVU-Ow-ZZ1" firstAttribute="top" secondItem="3En-Qt-cec" secondAttribute="top" id="y6B-Zz-jaH"/> + </constraints> + </view> + </subviews> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <constraints> + <constraint firstItem="Jn5-Yz-JFE" firstAttribute="leading" secondItem="3re-Oq-Oeh" secondAttribute="leading" id="2QU-Ry-Vaf"/> + <constraint firstAttribute="trailing" secondItem="3En-Qt-cec" secondAttribute="trailing" id="5TZ-dk-Hj1"/> + <constraint firstAttribute="bottom" secondItem="Jn5-Yz-JFE" secondAttribute="bottom" id="5px-PU-4rL"/> + <constraint firstItem="Jn5-Yz-JFE" firstAttribute="top" secondItem="3re-Oq-Oeh" secondAttribute="top" id="Qr0-yV-yMe"/> + <constraint firstItem="3En-Qt-cec" firstAttribute="top" secondItem="3re-Oq-Oeh" secondAttribute="top" id="hAv-ic-E23"/> + <constraint firstItem="3En-Qt-cec" firstAttribute="leading" secondItem="Jn5-Yz-JFE" secondAttribute="trailing" id="lOf-Tk-BGK"/> + <constraint firstAttribute="bottom" secondItem="3En-Qt-cec" secondAttribute="bottom" id="rfW-DT-eCX"/> + </constraints> + </view> + </subviews> + <constraints> + <constraint firstAttribute="width" constant="200" id="LWM-Hh-a5c"/> + <constraint firstAttribute="height" constant="60" id="qII-YM-o0M"/> + </constraints> + </stackView> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Working Days" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mtn-Bf-Lzt"> + <rect key="frame" x="10" y="180" width="355" height="24"/> + <constraints> + <constraint firstAttribute="height" constant="24" id="sfS-Df-JNB"/> + </constraints> + <fontDescription key="fontDescription" name="HelveticaNeue-Medium" family="Helvetica Neue" pointSize="18"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="Lqv-JL-JXU"> + <rect key="frame" x="10" y="89" width="355" height="61"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cxv-Rj-jyZ"> + <rect key="frame" x="0.0" y="0.0" width="355" height="20.333333333333332"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="zed-bF-ruL"> + <rect key="frame" x="0.0" y="20.333333333333329" width="355" height="20.333333333333329"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gvg-Dw-ZgB"> + <rect key="frame" x="0.0" y="40.666666666666657" width="355" height="20.333333333333329"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + </stackView> + </subviews> + <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <constraints> + <constraint firstItem="Mtn-Bf-Lzt" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="10" id="6rR-Hi-108"/> + <constraint firstItem="PDJ-dE-Eam" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="7NS-dJ-RgS"/> + <constraint firstItem="Mtn-Bf-Lzt" firstAttribute="top" secondItem="Lqv-JL-JXU" secondAttribute="bottom" constant="30" id="9A3-m1-k8r"/> + <constraint firstItem="caN-rO-3Wt" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="Bh0-SK-Ado"/> + <constraint firstItem="PDJ-dE-Eam" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="Bqf-hx-Yw0"/> + <constraint firstItem="zkz-CT-krb" firstAttribute="top" secondItem="Mtn-Bf-Lzt" secondAttribute="bottom" constant="10" id="I8d-Bw-0P5"/> + <constraint firstItem="zkz-CT-krb" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="10" id="Kca-EX-S4i"/> + <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="zkz-CT-krb" secondAttribute="trailing" constant="10" id="dTQ-4y-xTP"/> + <constraint firstItem="PDJ-dE-Eam" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="10" id="gGK-OI-5Xx"/> + <constraint firstItem="Lqv-JL-JXU" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" constant="30" id="grP-J9-8uD"/> + <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="Mtn-Bf-Lzt" secondAttribute="trailing" constant="10" id="hJg-RC-9FL"/> + <constraint firstItem="Lqv-JL-JXU" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="10" id="iZb-3f-mCq"/> + <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="Lqv-JL-JXU" secondAttribute="trailing" constant="10" id="j60-ZJ-z2v"/> + <constraint firstAttribute="trailing" secondItem="PDJ-dE-Eam" secondAttribute="trailing" constant="10" id="w5g-a2-K11"/> + <constraint firstItem="caN-rO-3Wt" firstAttribute="top" secondItem="zkz-CT-krb" secondAttribute="bottom" constant="20" id="ymL-rD-zly"/> + </constraints> + <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> + <point key="canvasLocation" x="8.3969465648854964" y="-89.436619718309871"/> + </view> + </objects> + <resources> + <systemColor name="systemBackgroundColor"> + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </systemColor> + </resources> +</document> diff --git a/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.swift b/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.swift new file mode 100644 index 0000000000000000000000000000000000000000..5873133d356c49d0861a2f399eea44b69333ebc4 --- /dev/null +++ b/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.swift @@ -0,0 +1,134 @@ +// +// TrackingView.swift +// TraccarClient +// +// Created by George Makhoul on 21/11/2023. +// Copyright © 2023 Traccar. All rights reserved. +// + +import UIKit + +final class TrackingView: KNComponentView { + // MARK: - Outlets + @IBOutlet var view: UIView! + @IBOutlet private weak var timeSlider: UISlider! + @IBOutlet private weak var connectionStatusLabel: UILabel! + @IBOutlet private weak var desc1Label: UILabel! + @IBOutlet private weak var desk2Label: UILabel! + @IBOutlet private weak var timeLeftLabel: UILabel! + @IBOutlet private weak var startTimeView: UIView! + @IBOutlet private weak var startTimeLabel: UILabel! + @IBOutlet private weak var endTimeView: UIView! + @IBOutlet private weak var endTimeLabel: UILabel! + @IBOutlet private weak var startShiftLabel: UILabel! + @IBOutlet private weak var endShiftLable: UILabel! + @IBOutlet private weak var workingTimeLable: UILabel! + + // MARK: - Properties + private var shift: ShiftModel? + var currentTime: Date! + var endTimeDate: Date! + var timer: Timer! + let timeFormat = "HH:mm" + let interval = 60.0 // 1 minute + + + // MARK: - Lifecycle + override func setupNib() { + super.setupNib() + + view.frame = bounds + view.autoresizingMask = [.flexibleHeight, .flexibleWidth] + + setupUI() + } + + private func setupUI() { + timeSlider.setThumbImage(.handle, for: .normal) + timeSlider.isUserInteractionEnabled = false + + connectionStatusLabel.set(text: "You're on the map!", color: .black, font: .bold(20)) + connectionStatusLabel.textAlignment = .center + + desc1Label.set(text: "Tracking will be working", color: .black, font: .regular(18)) + desc1Label.textAlignment = .center + + desk2Label.set(text: "until the end of your shift after", color: .black, font: .regular(18)) + desk2Label.textAlignment = .center + + timeLeftLabel.set(text: "3 hours 19 minutes", color: .black, font: .bold(18)) + timeLeftLabel.textAlignment = .center + + startTimeView.addCorners(4) + startTimeView.backgroundColor = .invalid + + endTimeView.addCorners(4) + endTimeView.backgroundColor = .invalid + + startTimeLabel.set(text: "09:00", color: .invalidText, font: .semibold(13)) + startTimeLabel.textAlignment = .center + + endTimeLabel.set(text: "17:00", color: .invalidText, font: .semibold(13)) + endTimeLabel.textAlignment = .center + + startShiftLabel.set(text: "Shift Starts", color: .invalid, font: .regular(11)) + startShiftLabel.textAlignment = .center + + endShiftLable.set(text: "Shift Ends", color: .invalid, font: .regular(11)) + + workingTimeLable.set(text: "Working Time: 03:24", color: .black, font: .medium(10)) + } + + func set(model: ShiftModel) { + shift = model + configureSlider(model: model) + setupTimer() + } + + func configureSlider(model: ShiftModel) { + self.startTimeLabel.text = model.timings[0].startsAt + self.endTimeLabel.text = model.timings[0].endsAt + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = timeFormat + + guard let startDate = dateFormatter.date(from: model.timings[0].startsAt), + let endDate = dateFormatter.date(from: model.timings[0].endsAt) else { + return + } + + currentTime = startDate + endTimeDate = endDate + + timeSlider.minimumValue = 0 + timeSlider.maximumValue = Float(endDate.timeIntervalSince(startDate) / interval) + 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() + } + } +} diff --git a/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.xib b/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.xib new file mode 100644 index 0000000000000000000000000000000000000000..eb83704322633843c23b8aaa6aaf3fd331b0bdf5 --- /dev/null +++ b/TraccarClient/MainViewController/CustomViews/TrackingView/TrackingView.xib @@ -0,0 +1,191 @@ +<?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_12" 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> + <objects> + <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="TrackingView" customModule="TraccarClient" customModuleProvider="target"> + <connections> + <outlet property="connectionStatusLabel" destination="rLp-PE-s4T" id="Wep-Rq-syl"/> + <outlet property="desc1Label" destination="Jha-Gg-NMv" id="XiW-f9-rKA"/> + <outlet property="desk2Label" destination="Xb4-NG-bL5" id="6Gi-lA-jlM"/> + <outlet property="endShiftLable" destination="bKc-Xn-QcK" id="p6j-kD-EvU"/> + <outlet property="endTimeLabel" destination="ioB-Sr-Z6C" id="3uJ-Cc-PKc"/> + <outlet property="endTimeView" destination="HDf-k7-6TD" id="tDL-Zz-EYV"/> + <outlet property="startShiftLabel" destination="08W-Eh-Epv" id="r7w-xC-rR3"/> + <outlet property="startTimeLabel" destination="Kcg-na-8FM" id="54N-fT-Sqe"/> + <outlet property="startTimeView" destination="xhu-2r-Ka7" id="kwE-vT-6m0"/> + <outlet property="timeLeftLabel" destination="dbF-ov-kWi" id="ayK-TL-ch0"/> + <outlet property="timeSlider" destination="hhI-Nt-wGT" id="0xK-93-hOM"/> + <outlet property="view" destination="iN0-l3-epB" id="YZe-17-skI"/> + <outlet property="workingTimeLable" destination="OMy-fH-7Fz" id="8tg-Ty-Cvt"/> + </connections> + </placeholder> + <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> + <view contentMode="scaleToFill" id="iN0-l3-epB"> + <rect key="frame" x="0.0" y="0.0" width="393" height="380"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="You're on the map!" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="rLp-PE-s4T"> + <rect key="frame" x="10" y="0.0" width="373" height="24"/> + <constraints> + <constraint firstAttribute="height" constant="24" id="VPa-YJ-oVa"/> + </constraints> + <fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="20"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="Gi1-js-H1e"> + <rect key="frame" x="10" y="74" width="373" height="61"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tracking will be working " textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jha-Gg-NMv"> + <rect key="frame" x="0.0" y="0.0" width="373" height="20.333333333333332"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="until the end of your shift after" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Xb4-NG-bL5"> + <rect key="frame" x="0.0" y="20.333333333333329" width="373" height="20.333333333333329"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="3 hours 19 minutes" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dbF-ov-kWi"> + <rect key="frame" x="0.0" y="40.666666666666671" width="373" height="20.333333333333329"/> + <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + </stackView> + <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="10" minValue="2" maxValue="15" translatesAutoresizingMaskIntoConstraints="NO" id="hhI-Nt-wGT"> + <rect key="frame" x="38" y="276" width="317" height="31"/> + <color key="minimumTrackTintColor" red="0.15686274509803921" green="0.7803921568627451" blue="0.43529411764705883" alpha="1" colorSpace="custom" customColorSpace="displayP3"/> + </slider> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xhu-2r-Ka7"> + <rect key="frame" x="21.666666666666671" y="254" width="53" height="22"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Kcg-na-8FM"> + <rect key="frame" x="0.0" y="0.0" width="53" height="22"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <constraints> + <constraint firstAttribute="bottom" secondItem="Kcg-na-8FM" secondAttribute="bottom" id="3L2-QM-JIB"/> + <constraint firstItem="Kcg-na-8FM" firstAttribute="leading" secondItem="xhu-2r-Ka7" secondAttribute="leading" id="GUL-cV-1nX"/> + <constraint firstAttribute="height" constant="22" id="KYp-kq-3n8"/> + <constraint firstAttribute="width" constant="53" id="L6v-28-LeP"/> + <constraint firstAttribute="trailing" secondItem="Kcg-na-8FM" secondAttribute="trailing" id="WbL-OC-CLI"/> + <constraint firstItem="Kcg-na-8FM" firstAttribute="top" secondItem="xhu-2r-Ka7" secondAttribute="top" id="mnM-be-ACO"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HDf-k7-6TD"> + <rect key="frame" x="319" y="254" width="53" height="22"/> + <subviews> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ioB-Sr-Z6C"> + <rect key="frame" x="0.0" y="0.0" width="53" height="22"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <constraints> + <constraint firstItem="ioB-Sr-Z6C" firstAttribute="top" secondItem="HDf-k7-6TD" secondAttribute="top" id="1ug-Cw-aAV"/> + <constraint firstAttribute="height" constant="22" id="8WE-P1-4zG"/> + <constraint firstAttribute="bottom" secondItem="ioB-Sr-Z6C" secondAttribute="bottom" id="Fka-fP-mP8"/> + <constraint firstItem="ioB-Sr-Z6C" firstAttribute="leading" secondItem="HDf-k7-6TD" secondAttribute="leading" id="bH2-Wh-B0S"/> + <constraint firstAttribute="width" constant="53" id="bj0-i5-qS5"/> + <constraint firstAttribute="trailing" secondItem="ioB-Sr-Z6C" secondAttribute="trailing" id="chl-XF-SfC"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="LVp-Uj-Nld"> + <rect key="frame" x="42" y="306" width="1" height="8"/> + <color key="backgroundColor" systemColor="opaqueSeparatorColor"/> + <constraints> + <constraint firstAttribute="width" constant="1" id="6Fp-08-lSs"/> + <constraint firstAttribute="height" constant="8" id="XBD-gr-iAC"/> + </constraints> + </view> + <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5tf-ff-6KW"> + <rect key="frame" x="350" y="306" width="1" height="8"/> + <color key="backgroundColor" systemColor="opaqueSeparatorColor"/> + <constraints> + <constraint firstAttribute="width" constant="1" id="FBP-dO-Fu6"/> + <constraint firstAttribute="height" constant="8" id="rta-uD-byG"/> + </constraints> + </view> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Shift start" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="08W-Eh-Epv"> + <rect key="frame" x="16.333333333333332" y="317" width="52.333333333333343" height="13.333333333333314"/> + <fontDescription key="fontDescription" type="system" pointSize="11"/> + <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Shift Ends" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bKc-Xn-QcK"> + <rect key="frame" x="323.66666666666669" y="317" width="53.666666666666686" height="13.333333333333314"/> + <fontDescription key="fontDescription" type="system" pointSize="11"/> + <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + <nil key="highlightedColor"/> + </label> + <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OMy-fH-7Fz"> + <rect key="frame" x="176" y="334.66666666666669" width="41.333333333333343" height="20.333333333333314"/> + <fontDescription key="fontDescription" type="system" pointSize="17"/> + <nil key="textColor"/> + <nil key="highlightedColor"/> + </label> + </subviews> + <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/> + <color key="backgroundColor" systemColor="systemBackgroundColor"/> + <constraints> + <constraint firstItem="bKc-Xn-QcK" firstAttribute="top" secondItem="5tf-ff-6KW" secondAttribute="bottom" constant="3" id="3a0-BM-Qok"/> + <constraint firstAttribute="bottom" secondItem="OMy-fH-7Fz" secondAttribute="bottom" constant="25" id="8uo-DC-1GN"/> + <constraint firstItem="OMy-fH-7Fz" firstAttribute="top" secondItem="hhI-Nt-wGT" secondAttribute="bottom" constant="28.670000000000002" id="Eyq-fE-3wv"/> + <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="Gi1-js-H1e" secondAttribute="trailing" constant="10" id="FD5-7e-cR3"/> + <constraint firstItem="xhu-2r-Ka7" firstAttribute="top" relation="lessThanOrEqual" secondItem="Gi1-js-H1e" secondAttribute="bottom" constant="119" id="KGe-hh-njU"/> + <constraint firstItem="xhu-2r-Ka7" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="21.5" id="O3x-q4-MVR"/> + <constraint firstItem="Gi1-js-H1e" firstAttribute="top" secondItem="rLp-PE-s4T" secondAttribute="bottom" constant="50" id="Oqv-eE-aew"/> + <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="HDf-k7-6TD" secondAttribute="trailing" constant="21" id="P53-4m-UOH"/> + <constraint firstAttribute="trailing" secondItem="rLp-PE-s4T" secondAttribute="trailing" constant="10" id="QSd-bc-Re9"/> + <constraint firstItem="vUN-kp-3ea" firstAttribute="bottom" secondItem="hhI-Nt-wGT" secondAttribute="bottom" constant="40" id="THB-jz-XWh"/> + <constraint firstItem="rLp-PE-s4T" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="10" id="URP-9g-svb"/> + <constraint firstItem="08W-Eh-Epv" firstAttribute="centerX" secondItem="LVp-Uj-Nld" secondAttribute="centerX" id="ZIR-Qo-DhR"/> + <constraint firstItem="bKc-Xn-QcK" firstAttribute="centerX" secondItem="5tf-ff-6KW" secondAttribute="centerX" id="aPc-tP-Csi"/> + <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="hhI-Nt-wGT" secondAttribute="trailing" constant="40" id="dtp-RJ-Ooq"/> + <constraint firstItem="hhI-Nt-wGT" firstAttribute="top" secondItem="xhu-2r-Ka7" secondAttribute="bottom" id="hdt-I3-NPo"/> + <constraint firstItem="Gi1-js-H1e" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="10" id="kak-em-6Nu"/> + <constraint firstItem="rLp-PE-s4T" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="n3s-NI-sj5"/> + <constraint firstItem="08W-Eh-Epv" firstAttribute="top" secondItem="LVp-Uj-Nld" secondAttribute="bottom" constant="3" id="nj8-Z1-Rf1"/> + <constraint firstItem="hhI-Nt-wGT" firstAttribute="top" secondItem="HDf-k7-6TD" secondAttribute="bottom" id="pjf-n2-sZX"/> + <constraint firstItem="5tf-ff-6KW" firstAttribute="trailing" secondItem="hhI-Nt-wGT" secondAttribute="trailing" constant="-2" id="q7M-zx-rRv"/> + <constraint firstItem="hhI-Nt-wGT" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="40" id="r8o-bt-gis"/> + <constraint firstItem="5tf-ff-6KW" firstAttribute="top" secondItem="hhI-Nt-wGT" secondAttribute="bottom" id="ult-c6-cie"/> + <constraint firstItem="OMy-fH-7Fz" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="vUi-l4-RxH"/> + <constraint firstItem="LVp-Uj-Nld" firstAttribute="leading" secondItem="hhI-Nt-wGT" secondAttribute="leading" constant="2" id="w2A-Kp-Dry"/> + <constraint firstItem="LVp-Uj-Nld" firstAttribute="top" secondItem="hhI-Nt-wGT" secondAttribute="bottom" id="zA1-lZ-ZDE"/> + </constraints> + <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/> + <variation key="default"> + <mask key="constraints"> + <exclude reference="THB-jz-XWh"/> + </mask> + </variation> + <point key="canvasLocation" x="139.69465648854961" y="-146.47887323943664"/> + </view> + </objects> + <resources> + <systemColor name="opaqueSeparatorColor"> + <color red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> + </systemColor> + <systemColor name="systemBackgroundColor"> + <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> + </systemColor> + </resources> +</document> diff --git a/TraccarClient/ShiftsModel.swift b/TraccarClient/ShiftsModel.swift index 290204a9c5dc78040f974fe8b0068e17c5c36d84..ee6040eab08eb87a2fcf02c085e2a6279e43b4c4 100644 --- a/TraccarClient/ShiftsModel.swift +++ b/TraccarClient/ShiftsModel.swift @@ -69,8 +69,15 @@ final class TimingModel: KNObject { super.init() id = dict["id"] as? Int ?? 0 - startsAt = dict["starts_at"] as? String ?? "" - endsAt = dict["ends_at"] as? String ?? "" + + var startStr = dict["starts_at"] as? String ?? "" + startStr.insert(":", at: startStr.index(startStr.startIndex, offsetBy: 2)) + startsAt = startStr + + var endStr = dict["ends_at"] as? String ?? "" + endStr.insert(":", at: endStr.index(endStr.startIndex, offsetBy: 2)) + endsAt = endStr + arrivalGracePeriod = dict["arrival_grace_period"] as? Int ?? 0 leavingGracePeriod = dict["leaving_grace_period"] as? Int ?? 0 breaks = dict["breaks"] as? String diff --git a/TraccarClient/UIImage.swift b/TraccarClient/UIImage.swift index e63158e962112adde541121522a834bc42282507..f4291e69b3209099e9662b2538e21252936c20c9 100644 --- a/TraccarClient/UIImage.swift +++ b/TraccarClient/UIImage.swift @@ -26,6 +26,7 @@ extension UIImage { static let updated = img("updated") static let thumbsDown = img("thumbDown") static let logout = img("logout") + static let handle = img("handle") } func img(_ name: String) -> UIImage {