From c5cf53bcf134e3a28e84d41025faf0d7f8d997bf Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:13:47 -0800 Subject: [PATCH 01/17] WIP Enhanced blowby capture --- ipad.xcodeproj/project.pbxproj | 36 +++++- ipad/Constants/StringConstants.swift | 6 +- ipad/Models/Shift/BlowbyModel.swift | 52 +++++++++ .../Shift/Form Fields/BlowbyFormHelper.swift | 60 ++++++++++ .../Shift/Form Fields/ShiftFormHelper.swift | 30 ----- ipad/Models/Shift/ShiftModel.swift | 34 ++++-- ...ShiftBlowbysHeaderCollectionViewCell.swift | 54 +++++++++ .../ShiftBlowbysHeaderCollectionViewCell.xib | 76 +++++++++++++ .../Header/BlowbyHeaderCollectionViewCell.xib | 77 +++++++++++++ ...verviewHeaderCollectionViewCell.storyboard | 30 +++++ .../BlowbyTableCollectionViewCell.swift | 104 ++++++++++++++++++ .../BlowbyTableCollectionViewCell.xib | 87 +++++++++++++++ .../InspectionsTableCollectionViewCell.xib | 8 +- .../Shift/ShiftViewController.swift | 58 +++++++++- 14 files changed, 665 insertions(+), 47 deletions(-) create mode 100644 ipad/Models/Shift/BlowbyModel.swift create mode 100644 ipad/Models/Shift/Form Fields/BlowbyFormHelper.swift create mode 100644 ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.swift create mode 100644 ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.xib create mode 100644 ipad/ViewControllers/Shift/Cells/Header/BlowbyHeaderCollectionViewCell.xib create mode 100644 ipad/ViewControllers/Shift/Cells/Header/BlowbyOverviewHeaderCollectionViewCell.storyboard create mode 100644 ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift create mode 100644 ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib diff --git a/ipad.xcodeproj/project.pbxproj b/ipad.xcodeproj/project.pbxproj index 27fd3ed6..aedaa9cf 100644 --- a/ipad.xcodeproj/project.pbxproj +++ b/ipad.xcodeproj/project.pbxproj @@ -186,6 +186,12 @@ 29FFEBBE237F1EAA00574E3F /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FFEBBD237F1EAA00574E3F /* Settings.swift */; }; 29FFEBC1237F1F6F00574E3F /* SettingsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FFEBC0237F1F6F00574E3F /* SettingsModel.swift */; }; 29FFEBC4237F23B800574E3F /* JWTDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29FFEBC3237F23B800574E3F /* JWTDecoder.swift */; }; + 41CAEC692B44A2C5002B2960 /* BlowbyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41CAEC682B44A2C5002B2960 /* BlowbyModel.swift */; }; + 41CAEC6B2B44AB0B002B2960 /* BlowbyFormHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41CAEC6A2B44AB0B002B2960 /* BlowbyFormHelper.swift */; }; + 41CAEC712B44BF19002B2960 /* BlowbyTableCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41CAEC702B44BF19002B2960 /* BlowbyTableCollectionViewCell.swift */; }; + 41CAEC732B44C1B1002B2960 /* BlowbyTableCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 41CAEC722B44C1B1002B2960 /* BlowbyTableCollectionViewCell.xib */; }; + 41CAEC7D2B45C538002B2960 /* ShiftBlowbysHeaderCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 41CAEC7C2B45C538002B2960 /* ShiftBlowbysHeaderCollectionViewCell.swift */; }; + 41CAEC7F2B45C54F002B2960 /* ShiftBlowbysHeaderCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 41CAEC7E2B45C54F002B2960 /* ShiftBlowbysHeaderCollectionViewCell.xib */; }; 5C0F6979237B635800F96CA5 /* WaterBodyAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C0F6978237B635800F96CA5 /* WaterBodyAPI.swift */; }; 5C0F697D237B683200F96CA5 /* CodesAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C0F697C237B683200F96CA5 /* CodesAPI.swift */; }; 5C0F6980237C6DDA00F96CA5 /* APIChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C0F697E237B6F7800F96CA5 /* APIChain.swift */; }; @@ -413,6 +419,12 @@ 29FFEBBD237F1EAA00574E3F /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; 29FFEBC0237F1F6F00574E3F /* SettingsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsModel.swift; sourceTree = ""; }; 29FFEBC3237F23B800574E3F /* JWTDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTDecoder.swift; sourceTree = ""; }; + 41CAEC682B44A2C5002B2960 /* BlowbyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlowbyModel.swift; sourceTree = ""; }; + 41CAEC6A2B44AB0B002B2960 /* BlowbyFormHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlowbyFormHelper.swift; sourceTree = ""; }; + 41CAEC702B44BF19002B2960 /* BlowbyTableCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlowbyTableCollectionViewCell.swift; sourceTree = ""; }; + 41CAEC722B44C1B1002B2960 /* BlowbyTableCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BlowbyTableCollectionViewCell.xib; sourceTree = ""; }; + 41CAEC7C2B45C538002B2960 /* ShiftBlowbysHeaderCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShiftBlowbysHeaderCollectionViewCell.swift; sourceTree = ""; }; + 41CAEC7E2B45C54F002B2960 /* ShiftBlowbysHeaderCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShiftBlowbysHeaderCollectionViewCell.xib; sourceTree = ""; }; 5C0F6978237B635800F96CA5 /* WaterBodyAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterBodyAPI.swift; sourceTree = ""; }; 5C0F697A237B63F500F96CA5 /* MusselAppAPITest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusselAppAPITest.swift; sourceTree = ""; }; 5C0F697C237B683200F96CA5 /* CodesAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodesAPI.swift; sourceTree = ""; }; @@ -592,6 +604,7 @@ children = ( 29DB4E4023870F2B00B13646 /* ShiftModel.swift */, 2944BCD92433931600826F48 /* Form Fields */, + 41CAEC682B44A2C5002B2960 /* BlowbyModel.swift */, ); path = Shift; sourceTree = ""; @@ -622,6 +635,7 @@ isa = PBXGroup; children = ( 296DEC22238C56A30035E7FA /* ShiftFormHelper.swift */, + 41CAEC6A2B44AB0B002B2960 /* BlowbyFormHelper.swift */, ); path = "Form Fields"; sourceTree = ""; @@ -676,6 +690,7 @@ 2944BCDF243394A300826F48 /* Cells */ = { isa = PBXGroup; children = ( + 41CAEC7B2B45C4AC002B2960 /* Blowbys */, 29DB4E422387111700B13646 /* Base */, 29DB4E432387112000B13646 /* Header */, 29DB4E4B238712ED00B13646 /* Inspections */, @@ -1259,6 +1274,8 @@ 29DB4E4B238712ED00B13646 /* Inspections */ = { isa = PBXGroup; children = ( + 41CAEC702B44BF19002B2960 /* BlowbyTableCollectionViewCell.swift */, + 41CAEC722B44C1B1002B2960 /* BlowbyTableCollectionViewCell.xib */, 29DB4E4C2387131000B13646 /* InspectionsTableCollectionViewCell.swift */, 29DB4E4D2387131000B13646 /* InspectionsTableCollectionViewCell.xib */, ); @@ -1374,6 +1391,15 @@ path = "JWT Decoder"; sourceTree = ""; }; + 41CAEC7B2B45C4AC002B2960 /* Blowbys */ = { + isa = PBXGroup; + children = ( + 41CAEC7C2B45C538002B2960 /* ShiftBlowbysHeaderCollectionViewCell.swift */, + 41CAEC7E2B45C54F002B2960 /* ShiftBlowbysHeaderCollectionViewCell.xib */, + ); + path = Blowbys; + sourceTree = ""; + }; 5C82D3D42374AECC00B065BA /* High Risk Modal */ = { isa = PBXGroup; children = ( @@ -1546,6 +1572,7 @@ 1EF7EBF223EC8E3E003886F6 /* WaterbodyPicker.xib in Resources */, 29F29F93236B6A22004F12E7 /* SwitcherView.xib in Resources */, 5C82D3D32374A0D400B065BA /* .gitignore in Resources */, + 41CAEC732B44C1B1002B2960 /* BlowbyTableCollectionViewCell.xib in Resources */, 5C82D3D72374AECC00B065BA /* HighRiskModalView.xib in Resources */, 2944AF9C2379B243007517DC /* ViewFieldCollectionViewCell.xib in Resources */, A7AE5275237CC3660044DBB7 /* unapproved-cross.json in Resources */, @@ -1601,6 +1628,7 @@ 5C649C922412F6E300F01AE5 /* GoogleService-Info.plist in Resources */, 1E54FFB623D783940044721F /* InputTitleCollectionViewCell.xib in Resources */, 29CE5E1D2375E48000C54F96 /* ConditionalInputCollectionViewCell.xib in Resources */, + 41CAEC7F2B45C54F002B2960 /* ShiftBlowbysHeaderCollectionViewCell.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1685,6 +1713,7 @@ 5C7D32F424304CFC00AFCE43 /* UIViewControllerExtensions.swift in Sources */, 29BAC5192367B34000A620F4 /* Fonts.swift in Sources */, 5C82D404237B31C200B065BA /* WatercraftRiskAssessmentAPI.swift in Sources */, + 41CAEC712B44BF19002B2960 /* BlowbyTableCollectionViewCell.swift in Sources */, 5C82D3D82374AECC00B065BA /* HighRiskModalView.swift in Sources */, 29BAC5102367984000A620F4 /* GradiantView.swift in Sources */, 291F918224742FD800974D33 /* WaterbodiesService.swift in Sources */, @@ -1695,6 +1724,7 @@ 295051092374D764000FBD6E /* DoubleInputCollectionViewCell.swift in Sources */, 5C82D3DD2374B9D700B065BA /* AppRemoteAPIConst.swift in Sources */, 29F29FA1236B8670004F12E7 /* DropdownCollectionViewCell.swift in Sources */, + 41CAEC6B2B44AB0B002B2960 /* BlowbyFormHelper.swift in Sources */, 29D5866925D20E6F00FEB37E /* MajorCitiesService.swift in Sources */, 29514BD92368ADB100DC89C4 /* OptionType.swift in Sources */, 290DA9E12404622700438699 /* AwaitingAccessResponse.swift in Sources */, @@ -1747,6 +1777,7 @@ 2933DD5E238DC2150068E9DF /* CodeTableService.swift in Sources */, 2933DD67238ED4470068E9DF /* ShiftService.swift in Sources */, 29FEA0A023FF12C200F490DB /* UserRoleModel.swift in Sources */, + 41CAEC692B44A2C5002B2960 /* BlowbyModel.swift in Sources */, 29DB4E3E23870B7B00B13646 /* ShifOverviewHeaderCollectionViewCell.swift in Sources */, 29DB4E462387113900B13646 /* BaseShiftOverviewCollectionViewCell.swift in Sources */, 5C82D3DF2374B9D700B065BA /* RemoteAPIManager.swift in Sources */, @@ -1798,6 +1829,7 @@ 298BF7CC2395D45C0072AA28 /* PreviousWaterBodyModel.swift in Sources */, 5C82D3DE2374B9D700B065BA /* RemoteAPI.swift in Sources */, 5C82D3F92376036700B065BA /* WorkflowAPI.swift in Sources */, + 41CAEC7D2B45C538002B2960 /* ShiftBlowbysHeaderCollectionViewCell.swift in Sources */, 29BAC51C2367B5B500A620F4 /* RealmRequests.swift in Sources */, 2950510D2374DFF7000FBD6E /* StringExtension.swift in Sources */, ); @@ -1997,7 +2029,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 383; + CURRENT_PROJECT_VERSION = 392; DEVELOPMENT_TEAM = L796QSLV3E; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = L796QSLV3E; ENABLE_BITCODE = NO; @@ -2027,7 +2059,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 383; + CURRENT_PROJECT_VERSION = 392; DEVELOPMENT_TEAM = L796QSLV3E; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = L796QSLV3E; ENABLE_BITCODE = NO; diff --git a/ipad/Constants/StringConstants.swift b/ipad/Constants/StringConstants.swift index b3bce126..b3add751 100644 --- a/ipad/Constants/StringConstants.swift +++ b/ipad/Constants/StringConstants.swift @@ -59,7 +59,11 @@ struct StringConstants { static let inspections: String = "" } } - +struct BlowbyFormHeaders { + static let blowByTime = "Blowby time" + static let watercraftComplexity = "Watercraft Complexity" + static let reportedToRapp = "Reported to RAPP" +} // MARK: Shift struct ShiftFormHeaders { struct ShiftStart { diff --git a/ipad/Models/Shift/BlowbyModel.swift b/ipad/Models/Shift/BlowbyModel.swift new file mode 100644 index 00000000..997b7c3a --- /dev/null +++ b/ipad/Models/Shift/BlowbyModel.swift @@ -0,0 +1,52 @@ +// +// BlowbyModel.swift +// ipad +// +// Created by Matthew Logan on 2024-01-02. +// Copyright © 2024 Amir Shayegh. All rights reserved. +// + +import Foundation +import Realm +import RealmSwift + +class BlowbyModel: Object, BaseRealmObject { + @objc dynamic var userId: String = ""; + @objc dynamic var localId: String = { + return UUID().uuidString + }() + @objc dynamic func primaryKey() -> String? { + return "localId" + } + @objc dynamic var timeStamp: Date = Date() + @objc dynamic var remoteId: Int = -1; + @objc dynamic var shouldSync: Bool = false + + @objc dynamic var reportedToRapp: Bool = false; + @objc dynamic var blowByTime: String = ""; + @objc dynamic var watercraftComplexity: String = "" + + func set(value: Any, for key: String) { + if self[key] == nil { + print("\(key) is nil"); + return + } + do { + let realm = try Realm() + try realm.write { + self[key] = value + } + } catch let error as NSError { + print("** REALM ERROR"); + print(error); + } + } + func toDictionary() -> [String : Any] { + return [ + "blowByTime": blowByTime, + "watercraftComplexity": watercraftComplexity, + "reportedToRapp": reportedToRapp + ] + } + +} diff --git a/ipad/Models/Shift/Form Fields/BlowbyFormHelper.swift b/ipad/Models/Shift/Form Fields/BlowbyFormHelper.swift new file mode 100644 index 00000000..b1433c30 --- /dev/null +++ b/ipad/Models/Shift/Form Fields/BlowbyFormHelper.swift @@ -0,0 +1,60 @@ +// +// BlowByFormHelper.swift +// ipad +// +// Created by Sustainment Team on 2023-12-29. +// Copyright © 2023 Sustainment Team. All rights reserved. +// + +import Foundation + +class BlowByFormHelper { + /// Form Headers for Blowby information in a shift + /// - Parameters: + /// - object: Model being used + /// - editable: Should the data display in a editable or static format? + /// - modalSize: Will be used in a scaled down + /// - Returns: [InputItems] + static func getBlowByStartFields(for object: BlowbyModel? = nil, editable: Bool? = true, modalSize: Bool? = false) -> [InputItem] { + var sectionItems: [InputItem] = [] + let blowByTime = TimeInput( + key: "blowByTime", + header: BlowbyFormHeaders.blowByTime, + editable: editable ?? true, + value: object?.blowByTime, + width: .Third + ); + sectionItems.append(blowByTime); + + let watercraftComplexity = DropdownInput ( + key: "watercraftComplexity", + header: BlowbyFormHeaders.watercraftComplexity, + editable: editable ?? true, + value: object?.watercraftComplexity, + width: .Third, + dropdownItems: DropdownHelper.shared.getDropdown(for: .stations) + ); + sectionItems.append(watercraftComplexity); + + let reportedToRapp = SwitchInput( + key: "reportedToRapp", + header: BlowbyFormHeaders.reportedToRapp, + editable: editable ?? true, + value: object?.reportedToRapp, + width: .Third + ); + sectionItems.append(reportedToRapp) + + return sectionItems; + } + + /// Column configuration for Blow By table + /// - Returns: [TableViewColumnConfig] + func getTableColumns() -> [TableViewColumnConfig] { + var columns: [TableViewColumnConfig] = [] + columns.append(TableViewColumnConfig(key: "blowByTime", header: BlowbyFormHeaders.blowByTime, type: .Normal)); + columns.append(TableViewColumnConfig(key: "watercraftComplexity", header: BlowbyFormHeaders.watercraftComplexity, type: .Normal)); + columns.append(TableViewColumnConfig(key: "reportedToRapp", header: BlowbyFormHeaders.reportedToRapp, type: .Normal)); + return columns; + } +} diff --git a/ipad/Models/Shift/Form Fields/ShiftFormHelper.swift b/ipad/Models/Shift/Form Fields/ShiftFormHelper.swift index 490fae75..89af7039 100644 --- a/ipad/Models/Shift/Form Fields/ShiftFormHelper.swift +++ b/ipad/Models/Shift/Form Fields/ShiftFormHelper.swift @@ -65,36 +65,6 @@ class ShiftFormHelper { ) sectionItems.append(k9OnShift) - let boatsInspected = SwitchInput( - key: "boatsInspected", - header: ShiftFormHeaders.ShiftEnd.boatsInspected, - editable: editable ?? true, - value: object?.boatsInspected, - width: .Third - ) - sectionItems.append(boatsInspected) - - let motorizedBlowBys = IntegerStepperInput( - key: "motorizedBlowBys", - header: ShiftFormHeaders.ShiftEnd.motorizedBlowBys, - editable: editable ?? true, - value: object?.motorizedBlowBys, - width: .Third - ) - sectionItems.append(motorizedBlowBys) - - let nonMotorizedBlowBys = IntegerStepperInput( - key: "nonMotorizedBlowBys", - header: ShiftFormHeaders.ShiftEnd.nonMotorizedBlowBys, - editable: editable ?? true, - value: object?.nonMotorizedBlowBys, - width: .Third - ) - sectionItems.append(nonMotorizedBlowBys) - - let spacer = InputSpacer() - sectionItems.append(spacer) - let shitEndComments = TextAreaInput( key: "shitEndComments", header: ShiftFormHeaders.ShiftEnd.comments, diff --git a/ipad/Models/Shift/ShiftModel.swift b/ipad/Models/Shift/ShiftModel.swift index 42d99977..bcd08dad 100644 --- a/ipad/Models/Shift/ShiftModel.swift +++ b/ipad/Models/Shift/ShiftModel.swift @@ -33,20 +33,17 @@ class ShiftModel: Object, BaseRealmObject { @objc dynamic var startTime: String = "" @objc dynamic var endTime: String = "" @objc dynamic var boatsInspected: Bool = true - @objc dynamic var motorizedBlowBys: Int = 0 - @objc dynamic var nonMotorizedBlowBys: Int = 0 @objc dynamic var k9OnShif: Bool = false @objc dynamic var date: Date? @objc dynamic var station: String = "" -// @objc dynamic var location: String = " " /// @objc dynamic var shitStartComments: String = "" @objc dynamic var shitEndComments: String = "" var inspections: List = List() - + var blowbys: List = List() @objc dynamic var status: String = "Draft" - // used for quary purposes (and displaying) + // used for query purposes (and displaying) @objc dynamic var formattedDate: String = "" // MARK: Save Object @@ -73,6 +70,23 @@ class ShiftModel: Object, BaseRealmObject { } } + func addBlowby() -> BlowbyModel? { + let blowby = BlowbyModel() + blowby.shouldSync = false; + blowby.userId = self.userId; + blowby.timeStamp = Date(); + do { + let realm = try Realm(); + try realm.write { + self.blowbys.append(blowby); + } + return blowby; + } catch let error as NSError { + print("** REALM ERROR"); + print(error); + return nil; + } + } // MARK: Setters func set(value: Any, for key: String) { if self[key] == nil { @@ -197,8 +211,6 @@ class ShiftModel: Object, BaseRealmObject { "location": "NA", "shiftStartComment": shitStartComments.count > 1 ? shitStartComments : "None", "shiftEndComment": shitEndComments.count > 1 ? shitEndComments : "None", - "motorizedBlowBys": motorizedBlowBys, - "nonMotorizedBlowBys": nonMotorizedBlowBys, "boatsInspected": boatsInspected, "k9OnShift": k9OnShif ] @@ -212,4 +224,12 @@ class ShiftModel: Object, BaseRealmObject { func getShiftEndFields(editable: Bool) -> [InputItem] { return ShiftFormHelper.getShiftEndFields(for: self, editable: editable) } + + func getBlowbyFields(editable: Bool) -> [[InputItem]] { + var blowbyfields: [[InputItem]] = []; + self.blowbys.forEach { blowby in + blowbyfields.append(BlowByFormHelper.getBlowByStartFields(for: blowby)) + } + return blowbyfields + } } diff --git a/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.swift new file mode 100644 index 00000000..4804b2e9 --- /dev/null +++ b/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.swift @@ -0,0 +1,54 @@ +// +// ShiftBlowBysHeaderCollectionViewCell.swift +// ipad +// +// Created by Amir Shayegh on 2019-11-21. +// Copyright © 2019 Amir Shayegh. All rights reserved. +// + +import UIKit + +class ShiftBlowBysHeaderCollectionViewCell: BaseShiftOverviewCollectionViewCell { + + // MARK: Outlets + @IBOutlet weak var addBlowByButton: UIButton! + @IBOutlet weak var divider: UIView! + @IBOutlet weak var titleLabel: UILabel! + + override func autofill() { + guard let model = self.model else {return} + if model.getStatus() != .Draft { + addBlowByButton.alpha = 0 + addBlowByButton.isEnabled = false + } + } + + // MARK: Outlet Actions + @IBAction func addBlowByClicked(_ sender: UIButton) { + if let callback = self.completion { + return callback() + } + } + + // MARK: Style + override func style() { + // Title + titleLabel.font = Fonts.getPrimaryBold(size: 24) + titleLabel.textColor = Colors.primary + // Button + styleFillButton(button: addBlowByButton) + // Divider + styleDivider(view: divider) + } + + private func colorFor(status: SyncableItemStatus) -> UIColor { + switch status { + case .PendingSync: + return Colors.Status.Yellow + case .Completed: + return Colors.Status.Green + case .Draft: + return Colors.Status.DarkGray + } + } +} diff --git a/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.xib b/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.xib new file mode 100644 index 00000000..8eca1da3 --- /dev/null +++ b/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.xib @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ipad/ViewControllers/Shift/Cells/Header/BlowbyHeaderCollectionViewCell.xib b/ipad/ViewControllers/Shift/Cells/Header/BlowbyHeaderCollectionViewCell.xib new file mode 100644 index 00000000..c190b6e4 --- /dev/null +++ b/ipad/ViewControllers/Shift/Cells/Header/BlowbyHeaderCollectionViewCell.xib @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ipad/ViewControllers/Shift/Cells/Header/BlowbyOverviewHeaderCollectionViewCell.storyboard b/ipad/ViewControllers/Shift/Cells/Header/BlowbyOverviewHeaderCollectionViewCell.storyboard new file mode 100644 index 00000000..dd79351e --- /dev/null +++ b/ipad/ViewControllers/Shift/Cells/Header/BlowbyOverviewHeaderCollectionViewCell.storyboard @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift new file mode 100644 index 00000000..5d084307 --- /dev/null +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift @@ -0,0 +1,104 @@ +// +// InspectionsTableCollectionViewCell.swift +// ipad +// +// Created by Amir Shayegh on 2019-11-21. +// Copyright © 2019 Amir Shayegh. All rights reserved. +// + +import UIKit + +class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell { + + // MARK: Constants + static let maxVisibleRows: CGFloat = 4 + + // MARK: Outlets + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var divider: UIView! + @IBOutlet weak var tableContainer: UIView! + @IBOutlet weak var tableHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var blowByButton: UIButton!; + // MARK: Class functions + override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { + let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes) + + // Specify you want _full width_ + let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0) + + // Calculate the size (height) using Auto Layout + let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.defaultHigh) + let autoLayoutFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: autoLayoutSize) + + // Assign the new size to the layout attributes + autoLayoutAttributes.frame = autoLayoutFrame + return autoLayoutAttributes + } + + @IBAction func addBlowbyClicked(_ sender: UIButton) { + if let callback = self.completion { + return callback() + } + } + // MARK: Setup + override func autofill() { + guard let model = self.model else {return} + let table = Table() + + // Convert list to array + let inspections: [BlowbyModel] = model.blowbys.map{ $0 } + + // Set table container height + tableHeightConstraint.constant = InspectionsTableCollectionViewCell.getTableHeight(for: model) + + // Create Column Config + var columns: [TableViewColumnConfig] = [] + columns.append(TableViewColumnConfig(key: "reportedToRapp", header: "Reported to Rapp", type: .Normal)) + columns.append(TableViewColumnConfig(key: "watercraftComplexity", header: "Watercraft Complexity", type: .Normal)) + columns.append(TableViewColumnConfig(key: "blowByTime", header: "Blowby time", type: .Normal)) + let tableView = table.show(columns: columns, in: inspections, container: tableContainer, emptyTitle: "It's looking a little empty around here.", emptyMessage: "You have not added any blowbys to this shift.") + tableView.layoutIfNeeded() + self.layoutIfNeeded() + } + + static func getContentHeight(for model: ShiftModel) -> CGFloat { + let titleHeight: CGFloat = 25 + let dividerHeight: CGFloat = 2 + let paddings: CGFloat = 8 * 4 + let totalVertialTitleSize = titleHeight + dividerHeight + paddings + return getTableHeight(for: model) + totalVertialTitleSize + } + + static func getTableHeight(for model: ShiftModel) -> CGFloat { + if model.inspections.isEmpty { + return 250 + } + // Convert list to array + + let inspections: [WatercraftInspectionModel] = model.inspections.map{ $0 } + let numberOfRows = inspections.count + + let rowHeight = Table.rowHeight + let headerHeight = Table.headerLabelHeight + + if numberOfRows < 1 { + return headerHeight + } + + // TODO: FIX IT + let extraDEBUG: CGFloat = 20 + + if CGFloat(numberOfRows) > maxVisibleRows { + return ( maxVisibleRows * (rowHeight + extraDEBUG)) + headerHeight + extraDEBUG + } else { + return ( CGFloat(numberOfRows) * (rowHeight + extraDEBUG)) + headerHeight + extraDEBUG + } + } + + // MARK: Style + override func style() { + styleSectionTitle(label: titleLabel) + styleDivider(view: divider) + } + +} diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib new file mode 100644 index 00000000..5ef4ec93 --- /dev/null +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/InspectionsTableCollectionViewCell.xib b/ipad/ViewControllers/Shift/Cells/Inspections/InspectionsTableCollectionViewCell.xib index df127dd6..c453ee7f 100644 --- a/ipad/ViewControllers/Shift/Cells/Inspections/InspectionsTableCollectionViewCell.xib +++ b/ipad/ViewControllers/Shift/Cells/Inspections/InspectionsTableCollectionViewCell.xib @@ -1,9 +1,9 @@ - - + + - + @@ -71,7 +71,7 @@ - + diff --git a/ipad/ViewControllers/Shift/ShiftViewController.swift b/ipad/ViewControllers/Shift/ShiftViewController.swift index 967622a0..a7beda9a 100644 --- a/ipad/ViewControllers/Shift/ShiftViewController.swift +++ b/ipad/ViewControllers/Shift/ShiftViewController.swift @@ -13,8 +13,13 @@ import UIKit private enum ShiftOverviewSectionRow: Int, CaseIterable { case Header case Inspections + case Blowbys } +private enum BlowbyOverviewSectionRow: Int, CaseIterable { + case Header + case Blowbys +} private enum ShiftInformationSectionRow: Int, CaseIterable { case Header case StartShift @@ -34,7 +39,9 @@ class ShiftViewController: BaseViewController { "BasicCollectionViewCell", "ShifOverviewHeaderCollectionViewCell", "InspectionsTableCollectionViewCell", - "ShiftInformationHeaderCollectionViewCell" + "BlowbyTableCollectionViewCell", + "ShiftInformationHeaderCollectionViewCell", + "ShiftBlowbysHeaderCollectionViewCell", ] // MARK: Varialbes @@ -42,6 +49,7 @@ class ShiftViewController: BaseViewController { var showShiftInfo: Bool = true var isEditable: Bool = true private var inspection: WatercraftInspectionModel? + private var blowby: BlowbyModel? // MARK: Outlets @IBOutlet weak var containerView: UIView! @@ -74,7 +82,10 @@ class ShiftViewController: BaseViewController { NotificationCenter.default.addObserver(self, selector: #selector(self.tableButtonClicked(notification:)), name: .TableButtonClicked, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.inputItemValueChanged(notification:)), name: .InputItemValueChanged, object: nil) } - + @objc func addBlowByClicked() { + Alert.show(title: "Add BlowBy!", message: "Now What?"); + self.model?.addBlowby(); + } func setup(model: ShiftModel) { self.model = model self.isEditable = model.getStatus() == .Draft || model.getStatus() == .PendingSync @@ -114,6 +125,10 @@ class ShiftViewController: BaseViewController { } } + @objc func addBlowbyClicked(sender: UIButton) { + Alert.show(title: "didTapAddBlowBy", message: "Yup"); + } + @objc func completeAction(sender: UIBarButtonItem) { guard let model = self.model else { return } self.dismissKeyboard() @@ -310,7 +325,13 @@ extension ShiftViewController: UICollectionViewDataSource, UICollectionViewDeleg func getShiftOverViewCell(indexPath: IndexPath) -> ShifOverviewHeaderCollectionViewCell { return collectionView!.dequeueReusableCell(withReuseIdentifier: "ShifOverviewHeaderCollectionViewCell", for: indexPath as IndexPath) as! ShifOverviewHeaderCollectionViewCell } - + func getShiftBlowbysHeaderCollectionViewCell(indexPath: IndexPath) -> ShiftBlowBysHeaderCollectionViewCell { + return collectionView!.dequeueReusableCell(withReuseIdentifier: "ShiftBlowBysHeaderCollectionViewCell", for: indexPath as IndexPath) as! ShiftBlowBysHeaderCollectionViewCell; + } + + func getBlowbyTableCell(indexPath: IndexPath) -> BlowbyTableCollectionViewCell { + return collectionView!.dequeueReusableCell(withReuseIdentifier: "BlowbyTableCollectionViewCell", for: indexPath as IndexPath) as! BlowbyTableCollectionViewCell + } func getInspectionsTableCell(indexPath: IndexPath) -> InspectionsTableCollectionViewCell { return collectionView!.dequeueReusableCell(withReuseIdentifier: "InspectionsTableCollectionViewCell", for: indexPath as IndexPath) as! InspectionsTableCollectionViewCell } @@ -360,6 +381,15 @@ extension ShiftViewController: UICollectionViewDataSource, UICollectionViewDeleg let cell = getInspectionsTableCell(indexPath: indexPath) cell.setup(object: model) return cell + case .Blowbys: + let cell = getBlowbyTableCell(indexPath: indexPath) + cell.setup(object: model, callback: {[weak self] in + guard let strongSelf = self else {return} + if strongSelf.isEditable { + strongSelf.addBlowByClicked() + } + }) + return cell } } @@ -388,6 +418,25 @@ extension ShiftViewController: UICollectionViewDataSource, UICollectionViewDeleg } } + func getBlowbyOverviewSectionRow(indexPath: IndexPath) -> UICollectionViewCell { + guard let rowType = BlowbyOverviewSectionRow(rawValue: Int(indexPath.row)), let model = self.model else {return UICollectionViewCell() } + switch rowType { + case .Header: + let cell = getShiftBlowbysHeaderCollectionViewCell(indexPath: indexPath) + cell.setup(object: model, callback: {[weak self] in + guard let strongSelf = self else {return} + if strongSelf.isEditable { + print("Yolo") + } + }) + return cell + case .Blowbys: + let cell = getBlowbyTableCell(indexPath: indexPath) + cell.setup(object: model) + return cell + } + } + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { guard let sectionType = ShiftViewSection(rawValue: Int(indexPath.section)) else { return CGSize(width: 0, height: 0) @@ -409,6 +458,9 @@ extension ShiftViewController: UICollectionViewDataSource, UICollectionViewDeleg case .Inspections: let height = InspectionsTableCollectionViewCell.getContentHeight(for: model) return CGSize(width: fullWidth, height: height) + case .Blowbys: + let height = BlowbyTableCollectionViewCell.getContentHeight(for: model) + return CGSize(width: fullWidth, height: height); } } From 6b465000b6d6471ebad4de7a664c74af747dcaff Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Wed, 3 Jan 2024 11:13:29 -0800 Subject: [PATCH 02/17] Positioned Blowby correctly in view --- .../Inspections/BlowbyTableCollectionViewCell.xib | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib index 5ef4ec93..7fbe951e 100644 --- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib @@ -13,7 +13,7 @@ - + @@ -42,10 +42,10 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From e4db99325c2e6b3bfb5f08ca02b5bdadb75cc919 Mon Sep 17 00:00:00 2001 From: David <62899351+davidclaveau@users.noreply.github.com> Date: Fri, 5 Jan 2024 13:24:01 -0800 Subject: [PATCH 09/17] update to add blowByTime as timestamp format --- ipad/Constants/StringConstants.swift | 2 +- ipad/Models/Shift/BlowbyModel.swift | 26 ++++- .../Shift/Form Fields/BlowbyFormHelper.swift | 12 +- ipad/Models/Shift/ShiftModel.swift | 3 +- .../BlowbyTableCollectionViewCell.swift | 2 +- .../New Blowby Modal/NewBlowbyModal.swift | 89 --------------- .../Views/New Blowby Modal/NewBlowbyModal.xib | 107 ------------------ 7 files changed, 32 insertions(+), 209 deletions(-) delete mode 100644 ipad/Views/New Blowby Modal/NewBlowbyModal.swift delete mode 100644 ipad/Views/New Blowby Modal/NewBlowbyModal.xib diff --git a/ipad/Constants/StringConstants.swift b/ipad/Constants/StringConstants.swift index b3add751..7e814c40 100644 --- a/ipad/Constants/StringConstants.swift +++ b/ipad/Constants/StringConstants.swift @@ -60,7 +60,7 @@ struct StringConstants { } } struct BlowbyFormHeaders { - static let blowByTime = "Blowby time" + static let timeStamp = "Blowby time" static let watercraftComplexity = "Watercraft Complexity" static let reportedToRapp = "Reported to RAPP" } diff --git a/ipad/Models/Shift/BlowbyModel.swift b/ipad/Models/Shift/BlowbyModel.swift index a1dbbe77..3a9b8b38 100644 --- a/ipad/Models/Shift/BlowbyModel.swift +++ b/ipad/Models/Shift/BlowbyModel.swift @@ -24,8 +24,9 @@ class BlowbyModel: Object, BaseRealmObject { @objc dynamic var remoteId: Int = -1 @objc dynamic var shouldSync: Bool = true - @objc dynamic var timeStamp: Date = Date() - + @objc dynamic var date: Date = Date() + @objc dynamic var timeStamp: String = "" + @objc dynamic var blowByTime: String = "" @objc dynamic var watercraftComplexity: String = "Non-Motorized" @objc dynamic var reportedToRapp: Bool = false @@ -51,19 +52,38 @@ class BlowbyModel: Object, BaseRealmObject { print(error) } } + func getThisBlowbyFields(editable: Bool, modalSize: Bool) -> [InputItem] { return BlowByFormHelper.getBlowByFields(for: self, editable: editable, modalSize: modalSize) } + + func formattedDateTime(time: String, date: Date) -> String? { + let timeFormatter = DateFormatter() + timeFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss" + timeFormatter.timeZone = TimeZone(abbreviation: "UTC") + let startDate = date + let startTimeSplit = time.components(separatedBy: ":") + guard let timeInDate = startDate.setTime(hour: Int(startTimeSplit[0]) ?? 0, min: Int(startTimeSplit[1]) ?? 0, sec: 1) else { + return nil + } + + return timeFormatter.string(from: timeInDate) + } + // MARK: - To Dictionary func toDictionary() -> [String : Any] { return toDictionary(shift: -1) } func toDictionary(shift id: Int) -> [String : Any] { + let date = self.date + guard let blowByTimeFormatted = formattedDateTime(time: timeStamp, date: date) else { + return [String : Any]() + } let body: [String: Any] = [ "observerWorkflowId": id, - "blowByTime": blowByTime, + "blowByTime": blowByTimeFormatted, "watercraftComplexity": watercraftComplexity, "reportedToRapp": reportedToRapp ] diff --git a/ipad/Models/Shift/Form Fields/BlowbyFormHelper.swift b/ipad/Models/Shift/Form Fields/BlowbyFormHelper.swift index 51ec0302..13f148d5 100644 --- a/ipad/Models/Shift/Form Fields/BlowbyFormHelper.swift +++ b/ipad/Models/Shift/Form Fields/BlowbyFormHelper.swift @@ -17,14 +17,14 @@ class BlowByFormHelper { /// - Returns: [InputItems] static func getBlowByFields(for object: BlowbyModel? = nil, editable: Bool? = true, modalSize: Bool? = false) -> [InputItem] { var sectionItems: [InputItem] = [] - let blowByTime = TimeInput( - key: "blowByTime", - header: BlowbyFormHeaders.blowByTime, + let timeStamp = TimeInput( + key: "timeStamp", + header: BlowbyFormHeaders.timeStamp, editable: editable ?? true, - value: object?.blowByTime, + value: object?.timeStamp, width: .Third ); - sectionItems.append(blowByTime); + sectionItems.append(timeStamp); let watercraftComplexity = DropdownInput ( key: "watercraftComplexity", @@ -57,7 +57,7 @@ class BlowByFormHelper { /// - Returns: [TableViewColumnConfig] func getTableColumns() -> [TableViewColumnConfig] { var columns: [TableViewColumnConfig] = [] - columns.append(TableViewColumnConfig(key: "blowByTime", header: BlowbyFormHeaders.blowByTime, type: .Normal)); + columns.append(TableViewColumnConfig(key: "timeStamp", header: BlowbyFormHeaders.timeStamp, type: .Normal)); columns.append(TableViewColumnConfig(key: "watercraftComplexity", header: BlowbyFormHeaders.watercraftComplexity, type: .Normal)); columns.append(TableViewColumnConfig(key: "reportedToRapp", header: BlowbyFormHeaders.reportedToRapp, type: .Normal)); return columns; diff --git a/ipad/Models/Shift/ShiftModel.swift b/ipad/Models/Shift/ShiftModel.swift index c2364a2c..263c0d76 100644 --- a/ipad/Models/Shift/ShiftModel.swift +++ b/ipad/Models/Shift/ShiftModel.swift @@ -41,7 +41,7 @@ class ShiftModel: Object, BaseRealmObject { /// @objc dynamic var shitStartComments: String = "" @objc dynamic var shitEndComments: String = "" - let BlowbyFields = ["reportedToRapp", "blowByTime", "watercraftComplexity"]; + let BlowbyFields = ["reportedToRapp", "timeStamp", "watercraftComplexity"]; var inspections: List = List() var blowbys: List = List() @objc dynamic var status: String = "Draft" @@ -75,7 +75,6 @@ class ShiftModel: Object, BaseRealmObject { func addBlowby(blowby: BlowbyModel) -> BlowbyModel? { blowby.shouldSync = true; blowby.userId = self.userId; - blowby.timeStamp = Date() do { let realm = try Realm(); try realm.write { diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift index cc61dccc..c62d609f 100644 --- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift @@ -55,7 +55,7 @@ class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell { var columns: [TableViewColumnConfig] = [] columns.append(TableViewColumnConfig(key: "reportedToRapp", header: "Reported to Rapp", type: .Normal)) columns.append(TableViewColumnConfig(key: "watercraftComplexity", header: "Watercraft Complexity", type: .Normal)) - columns.append(TableViewColumnConfig(key: "blowByTime", header: "Blowby Time", type: .Normal)) + columns.append(TableViewColumnConfig(key: "timeStamp", header: "Blowby Time", type: .Normal)) columns.append(TableViewColumnConfig(key: "", header: "Delete", type: .Button, buttonName: "Delete", showHeader: false)) let tableView = table.show(columns: columns, in: blowbys, container: tableContainer, emptyTitle: "It's looking a little empty around here.", emptyMessage: "You have not added any blowbys to this shift.") tableView.layoutIfNeeded() diff --git a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift deleted file mode 100644 index 0ff5c9f0..00000000 --- a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift +++ /dev/null @@ -1,89 +0,0 @@ -// -// NewBlowbyModal.swift -// ipad -// -// Created by Sustainment Team on 2023-01-04. -// Copyright © 2024 Sustainment Team. All rights reserved. -// - -import Foundation -import Modal - -class NewBlowbyModal: ModalView, Theme { - - // MARK: Variables - var onStart: ((_ model: ShiftModel) -> Void)? - var onCancel: (() -> Void)? - var model: ShiftModel? - var newBlowBy: BlowbyModel = BlowbyModel() - weak var inputGroup: UIView? - - // MARK: Outlets - @IBOutlet weak var iconImage: UIImageView! - @IBOutlet weak var headerLabel: UILabel! - @IBOutlet weak var divider: UIView! - @IBOutlet weak var cancelButton: UIButton! - @IBOutlet weak var startNowButton: UIButton! - @IBOutlet weak var inputContainer: UIView! - - @IBAction func cancelAction(_ sender: UIButton) { - guard let onClick = self.onCancel else {return} - self.remove() - return onClick() - } - - /// Action taken when the Confirmation button is pressed - @IBAction func startNowAction(_ sender: UIButton) { - guard let model = self.model, let onClick = self.onStart else {return} - //TODO: Add Validation Checks for Blowby - // If (Valid) Add Blowby, remove and return - _ = model.addBlowby(blowby: newBlowBy); - self.remove() - return onClick(model) - - } - - /// Entrance for modal, Initializer sets the model to the current shift we are editing in - func initialize(shift: ShiftModel, delegate: InputDelegate, onStart: @escaping (_ model: ShiftModel) -> Void, onCancel: @escaping () -> Void) { - self.onStart = onStart - self.onCancel = onCancel - setFixed(width: 550, height: 400) - present() - style() - - // Use the passed shift model instead of creating a new one - self.model = shift - - generateInput(delegate: delegate) - addListeners() - accessibilityLabel = "newShiftModal" - accessibilityValue = "newShiftModal" - } - - - private func addListeners() { - NotificationCenter.default.addObserver(self, selector: #selector(self.inputItemValueChanged(notification:)), name: .InputItemValueChanged, object: nil) - } - - // MARK: Input Item Changed - @objc func inputItemValueChanged(notification: Notification) { - guard let item: InputItem = notification.object as? InputItem else {return} - // Set value in Realm object - self.newBlowBy.set(value: item.value.get(type: item.type) as Any, for: item.key) - } - - func generateInput(delegate: InputDelegate) { - let fields = newBlowBy.getThisBlowbyFields(editable: true, modalSize: true) - self.inputGroup?.removeFromSuperview() - let inputGroup: InputGroupView = InputGroupView() - self.inputGroup = inputGroup - inputGroup.initialize(with: fields, delegate: delegate, in: inputContainer) - } - - func style() { - styleCard(layer: self.layer) - styleSectionTitle(label: headerLabel) - styleFillButton(button: startNowButton) - styleHollowButton(button: cancelButton) - } -} diff --git a/ipad/Views/New Blowby Modal/NewBlowbyModal.xib b/ipad/Views/New Blowby Modal/NewBlowbyModal.xib deleted file mode 100644 index f7acff8e..00000000 --- a/ipad/Views/New Blowby Modal/NewBlowbyModal.xib +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 848f453bf5f2e1c406495641200dc9ed778c0b1c Mon Sep 17 00:00:00 2001 From: David <62899351+davidclaveau@users.noreply.github.com> Date: Fri, 5 Jan 2024 17:38:47 -0800 Subject: [PATCH 10/17] add validation to blowby, fix button style, hide button if not draft --- ipad.xcodeproj/project.pbxproj | 16 +++ ipad/Models/Shift/BlowbyModel.swift | 2 +- ipad/Models/Shift/ShiftModel.swift | 14 +-- .../ShifOverviewHeaderCollectionViewCell.xib | 36 +++--- .../BlowbyTableCollectionViewCell.swift | 15 +++ .../BlowbyTableCollectionViewCell.xib | 24 ++-- .../InspectionsTableCollectionViewCell.xib | 12 +- .../Shift/ShiftViewController.swift | 42 ++++--- .../New Blowby Modal/NewBlowbyModal.swift | 103 +++++++++++++++++ .../Views/New Blowby Modal/NewBlowbyModal.xib | 107 ++++++++++++++++++ 10 files changed, 313 insertions(+), 58 deletions(-) create mode 100644 ipad/Views/New Blowby Modal/NewBlowbyModal.swift create mode 100644 ipad/Views/New Blowby Modal/NewBlowbyModal.xib diff --git a/ipad.xcodeproj/project.pbxproj b/ipad.xcodeproj/project.pbxproj index aedaa9cf..556e776e 100644 --- a/ipad.xcodeproj/project.pbxproj +++ b/ipad.xcodeproj/project.pbxproj @@ -214,6 +214,8 @@ 5C82D404237B31C200B065BA /* WatercraftRiskAssessmentAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C82D403237B31C200B065BA /* WatercraftRiskAssessmentAPI.swift */; }; 9620B078298849BF0084268C /* NullSwitchInputCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9620B076298849BF0084268C /* NullSwitchInputCollectionViewCell.swift */; }; 9620B079298849BF0084268C /* NullSwitchInputCollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9620B077298849BF0084268C /* NullSwitchInputCollectionViewCell.xib */; }; + 96CDB9632B4886FF009A45C7 /* NewBlowbyModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96CDB9612B4886FF009A45C7 /* NewBlowbyModal.swift */; }; + 96CDB9642B4886FF009A45C7 /* NewBlowbyModal.xib in Resources */ = {isa = PBXBuildFile; fileRef = 96CDB9622B4886FF009A45C7 /* NewBlowbyModal.xib */; }; A7AE5275237CC3660044DBB7 /* unapproved-cross.json in Resources */ = {isa = PBXBuildFile; fileRef = A7AE5272237CC3660044DBB7 /* unapproved-cross.json */; }; A7AE5276237CC3660044DBB7 /* check-mark-success.json in Resources */ = {isa = PBXBuildFile; fileRef = A7AE5273237CC3660044DBB7 /* check-mark-success.json */; }; A7AE5277237CC3660044DBB7 /* sync-circle.json in Resources */ = {isa = PBXBuildFile; fileRef = A7AE5274237CC3660044DBB7 /* sync-circle.json */; }; @@ -457,6 +459,8 @@ 763C8716EF742F6764FFE7D7 /* Pods-ipad.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ipad.debug.xcconfig"; path = "Target Support Files/Pods-ipad/Pods-ipad.debug.xcconfig"; sourceTree = ""; }; 9620B076298849BF0084268C /* NullSwitchInputCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NullSwitchInputCollectionViewCell.swift; sourceTree = ""; }; 9620B077298849BF0084268C /* NullSwitchInputCollectionViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NullSwitchInputCollectionViewCell.xib; sourceTree = ""; }; + 96CDB9612B4886FF009A45C7 /* NewBlowbyModal.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewBlowbyModal.swift; sourceTree = ""; }; + 96CDB9622B4886FF009A45C7 /* NewBlowbyModal.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NewBlowbyModal.xib; sourceTree = ""; }; 987374CFF5F2318652AA2FCC /* Pods-ipadTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ipadTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ipadTests/Pods-ipadTests.release.xcconfig"; sourceTree = ""; }; 99C48CD83AAD3AAA2CD083BF /* Pods-ipadTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ipadTests.release.xcconfig"; path = "Target Support Files/Pods-ipadTests/Pods-ipadTests.release.xcconfig"; sourceTree = ""; }; A41A1378A874E8BDB895F235 /* Pods-ipad.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ipad.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ipad/Pods-ipad.debug.xcconfig"; sourceTree = ""; }; @@ -754,6 +758,7 @@ 2944BCF52437C0EA00826F48 /* Views */ = { isa = PBXGroup; children = ( + 96CDB9602B4886FF009A45C7 /* New Blowby Modal */, 2968859026030F9D00ECA183 /* Major Cities Picker */, 2907E4B52368D21D00946B3F /* Input Modal */, 29A97437236FD615006C668F /* Form */, @@ -1462,6 +1467,15 @@ path = "Null Switch Input"; sourceTree = ""; }; + 96CDB9602B4886FF009A45C7 /* New Blowby Modal */ = { + isa = PBXGroup; + children = ( + 96CDB9612B4886FF009A45C7 /* NewBlowbyModal.swift */, + 96CDB9622B4886FF009A45C7 /* NewBlowbyModal.xib */, + ); + path = "New Blowby Modal"; + sourceTree = ""; + }; A7AE5271237CC3660044DBB7 /* LottieAnimations */ = { isa = PBXGroup; children = ( @@ -1606,6 +1620,7 @@ 295051112374F54A000FBD6E /* IntegerInputCollectionViewCell.xib in Resources */, 299BF02023FCA19A001732CD /* pdfMap.pdf in Resources */, 294D8F6223847C9A0094090D /* TableRowTableViewCell.xib in Resources */, + 96CDB9642B4886FF009A45C7 /* NewBlowbyModal.xib in Resources */, 296885B526030FE900ECA183 /* MajorCityPicker.xib in Resources */, F5EB30A127B5C77400F22712 /* Main.storyboard in Resources */, A7AE5276237CC3660044DBB7 /* check-mark-success.json in Resources */, @@ -1712,6 +1727,7 @@ 296DEC27238C61A80035E7FA /* IntegerStepperInputCollectionViewCell.swift in Sources */, 5C7D32F424304CFC00AFCE43 /* UIViewControllerExtensions.swift in Sources */, 29BAC5192367B34000A620F4 /* Fonts.swift in Sources */, + 96CDB9632B4886FF009A45C7 /* NewBlowbyModal.swift in Sources */, 5C82D404237B31C200B065BA /* WatercraftRiskAssessmentAPI.swift in Sources */, 41CAEC712B44BF19002B2960 /* BlowbyTableCollectionViewCell.swift in Sources */, 5C82D3D82374AECC00B065BA /* HighRiskModalView.swift in Sources */, diff --git a/ipad/Models/Shift/BlowbyModel.swift b/ipad/Models/Shift/BlowbyModel.swift index 3a9b8b38..7c034e6c 100644 --- a/ipad/Models/Shift/BlowbyModel.swift +++ b/ipad/Models/Shift/BlowbyModel.swift @@ -28,7 +28,7 @@ class BlowbyModel: Object, BaseRealmObject { @objc dynamic var timeStamp: String = "" @objc dynamic var blowByTime: String = "" - @objc dynamic var watercraftComplexity: String = "Non-Motorized" + @objc dynamic var watercraftComplexity: String = "" @objc dynamic var reportedToRapp: Bool = false // MARK: Setters diff --git a/ipad/Models/Shift/ShiftModel.swift b/ipad/Models/Shift/ShiftModel.swift index 263c0d76..4af45709 100644 --- a/ipad/Models/Shift/ShiftModel.swift +++ b/ipad/Models/Shift/ShiftModel.swift @@ -194,16 +194,16 @@ class ShiftModel: Object, BaseRealmObject { return timeFormatter.string(from: timeInDate) } - func deleteBlowby(blowbyToDelete: BlowbyModel) -> Void { + func deleteBlowby(blowbyToDelete: BlowbyModel) -> Void { // Open a write transaction do { - let realm = try Realm() - try realm.write { - // Delete the object from Realm - realm.delete(blowbyToDelete) - } + let realm = try Realm() + try realm.write { + // Delete the object from Realm + realm.delete(blowbyToDelete) + } } catch { - print("Error deleting blowby: \(error)") + print("Error deleting blowby: \(error)") } } diff --git a/ipad/ViewControllers/Shift/Cells/Header/ShifOverviewHeaderCollectionViewCell.xib b/ipad/ViewControllers/Shift/Cells/Header/ShifOverviewHeaderCollectionViewCell.xib index 222767a3..6d8d5f0c 100644 --- a/ipad/ViewControllers/Shift/Cells/Header/ShifOverviewHeaderCollectionViewCell.xib +++ b/ipad/ViewControllers/Shift/Cells/Header/ShifOverviewHeaderCollectionViewCell.xib @@ -1,23 +1,24 @@ - - + + - + + - + - - + - + - - + + + @@ -87,7 +89,6 @@ - @@ -98,7 +99,12 @@ - + + + + + + diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift index c62d609f..857ab3c0 100644 --- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift @@ -57,7 +57,16 @@ class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell { columns.append(TableViewColumnConfig(key: "watercraftComplexity", header: "Watercraft Complexity", type: .Normal)) columns.append(TableViewColumnConfig(key: "timeStamp", header: "Blowby Time", type: .Normal)) columns.append(TableViewColumnConfig(key: "", header: "Delete", type: .Button, buttonName: "Delete", showHeader: false)) + + // Disable adding blowbys if not completed and hide delete button + if model.getStatus() != .Draft { + columns.removeLast() + blowByButton.alpha = 0 + blowByButton.isEnabled = false + } + let tableView = table.show(columns: columns, in: blowbys, container: tableContainer, emptyTitle: "It's looking a little empty around here.", emptyMessage: "You have not added any blowbys to this shift.") + tableView.layoutIfNeeded() self.layoutIfNeeded() } @@ -98,6 +107,12 @@ class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell { // MARK: Style override func style() { + // Title + titleLabel.font = Fonts.getPrimaryBold(size: 28) + titleLabel.textColor = Colors.primary + // Button + styleFillButton(button: blowByButton) + styleSectionTitle(label: titleLabel) styleDivider(view: divider) } diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib index c9e8d1c0..531c03b2 100644 --- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib @@ -1,9 +1,9 @@ - + - + @@ -18,10 +18,10 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1b5d9ee097912876b650da43aa31b0c6754f67bc Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Mon, 8 Jan 2024 08:17:47 -0800 Subject: [PATCH 11/17] Added refresh when new blowby added, removed validation check on reportedToRapp, cleaned table --- ipad/Models/Shift/BlowbyModel.swift | 6 ++++++ .../Inspections/BlowbyTableCollectionViewCell.swift | 2 +- ipad/ViewControllers/Shift/ShiftViewController.swift | 12 ++++++++---- ipad/Views/New Blowby Modal/NewBlowbyModal.swift | 5 ++--- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/ipad/Models/Shift/BlowbyModel.swift b/ipad/Models/Shift/BlowbyModel.swift index 7c034e6c..6fda7b1d 100644 --- a/ipad/Models/Shift/BlowbyModel.swift +++ b/ipad/Models/Shift/BlowbyModel.swift @@ -30,6 +30,7 @@ class BlowbyModel: Object, BaseRealmObject { @objc dynamic var blowByTime: String = "" @objc dynamic var watercraftComplexity: String = "" @objc dynamic var reportedToRapp: Bool = false + @objc dynamic var formattedReporttoRapp: String = "False" // MARK: Setters func set(value: Any, for key: String) { @@ -38,6 +39,11 @@ class BlowbyModel: Object, BaseRealmObject { return } self[key] = value + if key == "reportedToRapp" { + if let reported = value as? Bool { + formattedReporttoRapp = reported ? "True" : "False"; + } + } } diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift index 857ab3c0..157c9ce5 100644 --- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift @@ -53,7 +53,7 @@ class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell { // Create Column Config var columns: [TableViewColumnConfig] = [] - columns.append(TableViewColumnConfig(key: "reportedToRapp", header: "Reported to Rapp", type: .Normal)) + columns.append(TableViewColumnConfig(key: "formattedReporttoRapp", header: "Reported to Rapp", type: .Normal)) columns.append(TableViewColumnConfig(key: "watercraftComplexity", header: "Watercraft Complexity", type: .Normal)) columns.append(TableViewColumnConfig(key: "timeStamp", header: "Blowby Time", type: .Normal)) columns.append(TableViewColumnConfig(key: "", header: "Delete", type: .Button, buttonName: "Delete", showHeader: false)) diff --git a/ipad/ViewControllers/Shift/ShiftViewController.swift b/ipad/ViewControllers/Shift/ShiftViewController.swift index 9e8c765f..0e7a3389 100644 --- a/ipad/ViewControllers/Shift/ShiftViewController.swift +++ b/ipad/ViewControllers/Shift/ShiftViewController.swift @@ -86,18 +86,23 @@ class ShiftViewController: BaseViewController { @objc func addBlowByClicked() { let blowbyModal: NewBlowbyModal = NewBlowbyModal.fromNib() + blowbyModal.onSubmit = { [weak self] in + // Refresh the screen when data is submitted + self?.refreshScreen() + } guard let currentShiftModel = model else { return } blowbyModal.initialize(shift: currentShiftModel, delegate: self, onStart: { [weak self] (model) in guard let _self = self else { return } - // Handle the start action }) { // Canceled } + } + + func refreshScreen(){ self.view.setNeedsDisplay() self.viewWillAppear(true) } - func setup(model: ShiftModel) { self.model = model self.isEditable = model.getStatus() == .Draft || model.getStatus() == .PendingSync @@ -143,8 +148,7 @@ class ShiftViewController: BaseViewController { Alert.show(title: "Deleting Blowby", message: "Would you like to delete this Blowby?", yes: { model.deleteBlowby(blowbyToDelete: blowbyToDelete); - self.view.setNeedsDisplay() - self.viewWillAppear(true) + self.refreshScreen() }) { return } diff --git a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift index ca8b733c..891088db 100644 --- a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift +++ b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift @@ -14,6 +14,7 @@ class NewBlowbyModal: ModalView, Theme { // MARK: Variables var onStart: ((_ model: ShiftModel) -> Void)? var onCancel: (() -> Void)? + var onSubmit: (() -> Void)? var model: ShiftModel? var newBlowBy: BlowbyModel = BlowbyModel() weak var inputGroup: UIView? @@ -38,9 +39,6 @@ class NewBlowbyModal: ModalView, Theme { // If (Valid) Add Blowby, remove and return var invalidFields: [String] = [] - if !newBlowBy.reportedToRapp { - invalidFields.append("Reported to RAPP") - } if newBlowBy.watercraftComplexity == "" { invalidFields.append("Watercraft Complexity") } @@ -52,6 +50,7 @@ class NewBlowbyModal: ModalView, Theme { Alert.show(title: "Can't continue", message: "Please complete the following fields: " + invalidFields.joined(separator: ", ")) } else { _ = model.addBlowby(blowby: newBlowBy); + onSubmit?() self.remove() return onClick(model) } From 57a0e1c16b5c37ec32602b7c052459ddcff18d9b Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Mon, 8 Jan 2024 13:18:57 -0800 Subject: [PATCH 12/17] Added New Entry/Edit logic to Blowby captures --- ipad/Models/Shift/BlowbyModel.swift | 49 ++++++++-- .../BlowbyTableCollectionViewCell.swift | 2 +- .../BlowbyTableCollectionViewCell.xib | 6 +- .../Shift/ShiftViewController.swift | 48 ++++++--- .../New Blowby Modal/NewBlowbyModal.swift | 97 +++++++++++++------ 5 files changed, 147 insertions(+), 55 deletions(-) diff --git a/ipad/Models/Shift/BlowbyModel.swift b/ipad/Models/Shift/BlowbyModel.swift index 6fda7b1d..f84b0d5a 100644 --- a/ipad/Models/Shift/BlowbyModel.swift +++ b/ipad/Models/Shift/BlowbyModel.swift @@ -30,9 +30,14 @@ class BlowbyModel: Object, BaseRealmObject { @objc dynamic var blowByTime: String = "" @objc dynamic var watercraftComplexity: String = "" @objc dynamic var reportedToRapp: Bool = false - @objc dynamic var formattedReporttoRapp: String = "False" + @objc dynamic var formattedReporttoRapp: String = "No" // MARK: Setters + + /// Setter method for BlowbyModel, used when new Blowbys are created, as they are not Realm objects + /// - Parameters: + /// - value: value to change Models key to + /// - key: Text representation of the key to be changed in the model func set(value: Any, for key: String) { if self[key] == nil { print("\(key) is nil") @@ -41,12 +46,34 @@ class BlowbyModel: Object, BaseRealmObject { self[key] = value if key == "reportedToRapp" { if let reported = value as? Bool { - formattedReporttoRapp = reported ? "True" : "False"; + formattedReporttoRapp = reported ? "Yes" : "No"; } } } - - + + /// Setter method for BlowbyModel, used when editing a new Blowby, since Realm objects must be edited in a write transaction + /// - Parameters: + /// - value: Value to change Models key to + /// - key: Text representation of the key to be changed in the model + func editSet(value: Any, for key: String) { + do { + let realm = try Realm() + try realm.write { + self[key] = value; + if key == "reportedToRapp" { + if let reported = value as? Bool { + formattedReporttoRapp = reported ? "Yes" : "No"; + } + } + } + } catch let error as NSError { + print("** REALM ERROR") + print(error) + } + } + + /// Function for setting RemoteID of Object managed by Realm + /// - Parameter remoteId: remoteID Integer func set(remoteId: Int) { do { let realm = try Realm() @@ -58,11 +85,21 @@ class BlowbyModel: Object, BaseRealmObject { print(error) } } - + + /// Returns Blowby fields set to this instance of object + /// - Parameters: + /// - editable: Boolean for determining if values can be edited, or remain static + /// - modalSize: Boolean to determine if Large or small size of input fields are returned + /// - Returns: Array of InputItems tailored to this model instance func getThisBlowbyFields(editable: Bool, modalSize: Bool) -> [InputItem] { return BlowByFormHelper.getBlowByFields(for: self, editable: editable, modalSize: modalSize) } - + + /// <#Description#> + /// - Parameters: + /// - time: <#time description#> + /// - date: <#date description#> + /// - Returns: <#description#> func formattedDateTime(time: String, date: Date) -> String? { let timeFormatter = DateFormatter() timeFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss" diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift index 157c9ce5..dc8c1b2f 100644 --- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift @@ -56,7 +56,7 @@ class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell { columns.append(TableViewColumnConfig(key: "formattedReporttoRapp", header: "Reported to Rapp", type: .Normal)) columns.append(TableViewColumnConfig(key: "watercraftComplexity", header: "Watercraft Complexity", type: .Normal)) columns.append(TableViewColumnConfig(key: "timeStamp", header: "Blowby Time", type: .Normal)) - columns.append(TableViewColumnConfig(key: "", header: "Delete", type: .Button, buttonName: "Delete", showHeader: false)) + columns.append(TableViewColumnConfig(key: "", header: "Edit", type: .Button, buttonName: "Edit", showHeader: false)) // Disable adding blowbys if not completed and hide delete button if model.getStatus() != .Draft { diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib index 531c03b2..b1e371be 100644 --- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib +++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.xib @@ -1,9 +1,9 @@ - + - + @@ -81,7 +81,7 @@ - + diff --git a/ipad/ViewControllers/Shift/ShiftViewController.swift b/ipad/ViewControllers/Shift/ShiftViewController.swift index 0e7a3389..74aaba65 100644 --- a/ipad/ViewControllers/Shift/ShiftViewController.swift +++ b/ipad/ViewControllers/Shift/ShiftViewController.swift @@ -84,6 +84,8 @@ class ShiftViewController: BaseViewController { NotificationCenter.default.addObserver(self, selector: #selector(self.inputItemValueChanged(notification:)), name: .InputItemValueChanged, object: nil) } + + /// Handler for when 'Add Blowby' is pressed. Brings up the shift modal, and refreshing the screen on submit action @objc func addBlowByClicked() { let blowbyModal: NewBlowbyModal = NewBlowbyModal.fromNib() blowbyModal.onSubmit = { [weak self] in @@ -142,17 +144,35 @@ class ShiftViewController: BaseViewController { } } - @objc func didTapDeleteBlowbyButton(blowbyToDelete: BlowbyModel) { - guard let model = self.model else { return } - self.dismissKeyboard() - - Alert.show(title: "Deleting Blowby", message: "Would you like to delete this Blowby?", yes: { - model.deleteBlowby(blowbyToDelete: blowbyToDelete); - self.refreshScreen() - }) { - return - } + @objc func didTapBlowbyToggle(blowbyToEdit: BlowbyModel){ + Alert.show(title: "Row tapped", message: "Action continues") + } + + + /// Handler for Edit button in Blowby table section. Brings up the modal with the existing Blowby so user can submit new data + /// - Parameter blowbyToEdit: Blowby to populate the view, allowing editing to occur on the model + @objc func didTapEditBlowbyButton(blowbyToEdit: BlowbyModel) { + let blowbyModal: NewBlowbyModal = NewBlowbyModal.fromNib() + blowbyModal.onSubmit = { [weak self] in + // Refresh the screen when data is submitted + self?.refreshScreen() + } + guard let currentShiftModel = model else { return } + blowbyModal.initialize(shift: currentShiftModel, newBlowby: blowbyToEdit, delegate: self, onStart: { [weak self] (model) in + guard let _self = self else { return } + }) { + // Canceled + } } + + /// Handler to delete a Blowby from the Shift + /// - Parameter blowbyToDelete: Instance of Blowby model that will be removed via realm + @objc func deleteBlowby(blowbyToDelete: BlowbyModel) { + guard let model = self.model else { return } + self.dismissKeyboard() + model.deleteBlowby(blowbyToDelete: blowbyToDelete); + self.refreshScreen() + } @objc func completeAction(sender: UIBarButtonItem) { guard let model = self.model else { return } @@ -176,12 +196,8 @@ class ShiftViewController: BaseViewController { @objc func tableButtonClicked(notification: Notification) { guard let actionModel = notification.object as? TableClickActionModel else {return} -// if actionModel.buttonName.lowercased() == "edit", let blowbyModel = actionModel.object as? BlowbyModel { -// didTapEditBlowbyButton(blowbyToEdit: blowbyModel); -// } - - if actionModel.buttonName.lowercased() == "delete", let blowbyModel = actionModel.object as? BlowbyModel { - didTapDeleteBlowbyButton(blowbyToDelete: blowbyModel); + if actionModel.buttonName.lowercased() == "edit", let blowbyModel = actionModel.object as? BlowbyModel { + didTapEditBlowbyButton(blowbyToEdit: blowbyModel); } if let inspectionModel = actionModel.object as? WatercraftInspectionModel { diff --git a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift index 891088db..bad9d2b9 100644 --- a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift +++ b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift @@ -8,6 +8,7 @@ import Foundation import Modal +import UIKit class NewBlowbyModal: ModalView, Theme { @@ -16,8 +17,9 @@ class NewBlowbyModal: ModalView, Theme { var onCancel: (() -> Void)? var onSubmit: (() -> Void)? var model: ShiftModel? - var newBlowBy: BlowbyModel = BlowbyModel() + var newBlowBy: BlowbyModel? weak var inputGroup: UIView? + var editingBlowby: Bool = false; // MARK: Outlets @IBOutlet weak var iconImage: UIImageView! @@ -26,53 +28,86 @@ class NewBlowbyModal: ModalView, Theme { @IBOutlet weak var cancelButton: UIButton! @IBOutlet weak var startNowButton: UIButton! @IBOutlet weak var inputContainer: UIView! - + + /// When cancel button is pressed, responds by closing modal @IBAction func cancelAction(_ sender: UIButton) { guard let onClick = self.onCancel else {return} self.remove() return onClick() } - - /// Action taken when the Confirmation button is pressed + + /// When delete button is pressed, sends confirmation for users action then deletes Blowby from list + @IBAction func deleteAction(_ sender: UIButton) { + Alert.show(title: "Deleting Blowby", message: "Would you like to delete this Blowby?", yes: { + self.model?.deleteBlowby(blowbyToDelete: self.newBlowBy!) + self.onSubmit?() + self.remove() + }) { + return + } + + } + + /// When button is pressed, validates information in the BlowbyModel, alerting user of unfilled fields + /// If we are not in edit mode, new BlowbyModel is appended to list of blowbys, and modal closes + /// If we are in in edit mode, Modal only closes. @IBAction func startNowAction(_ sender: UIButton) { guard let model = self.model, let onClick = self.onStart else {return} // If (Valid) Add Blowby, remove and return var invalidFields: [String] = [] - if newBlowBy.watercraftComplexity == "" { - invalidFields.append("Watercraft Complexity") - } - if newBlowBy.timeStamp == "" { + if newBlowBy!.timeStamp == "" { invalidFields.append("Blowby Time") } - + if newBlowBy!.watercraftComplexity == "" { + invalidFields.append("Watercraft Complexity") + } if !invalidFields.isEmpty { - Alert.show(title: "Can't continue", message: "Please complete the following fields: " + invalidFields.joined(separator: ", ")) + Alert.show(title: "Can't continue", message: "Please complete the following fields:\n-" + invalidFields.joined(separator: "\n-")) } else { - _ = model.addBlowby(blowby: newBlowBy); + if(!editingBlowby){ + _ = model.addBlowby(blowby: newBlowBy!); + } onSubmit?() self.remove() return onClick(model) } } - /// Entrance for modal, Initializer sets the model to the current shift we are editing in - func initialize(shift: ShiftModel, delegate: InputDelegate, onStart: @escaping (_ model: ShiftModel) -> Void, onCancel: @escaping () -> Void) { - self.onStart = onStart - self.onCancel = onCancel - setFixed(width: 550, height: 400) - present() - style() - - // Use the passed shift model instead of creating a new one - self.model = shift - - generateInput(delegate: delegate) - addListeners() - accessibilityLabel = "newShiftModal" - accessibilityValue = "newShiftModal" + /// Entry for Modal view, Sets modal to editing mode if a Blowby modal is passed in as argument, else remains in create mode. + func initialize(shift: ShiftModel, newBlowby: BlowbyModel? = BlowbyModel(), delegate: InputDelegate, onStart: @escaping (_ model: ShiftModel) -> Void, onCancel: @escaping () -> Void) { + self.onStart = onStart + self.onCancel = onCancel + setFixed(width: 550, height: 400); + present(); + style(); + + //Give the modal a refernce to the current shift, and set the Blowby + self.model = shift; + self.newBlowBy = newBlowby; + // since a valid modal would have a timeStamp passed in, we can determine if this is an empty model or an existing one + self.editingBlowby = newBlowBy!.timeStamp != ""; + if(self.editingBlowby) { + editingMode(); + } + generateInput(delegate: delegate); + addListeners(); + accessibilityLabel = "newShiftModal"; + accessibilityValue = "newShiftModal"; + } + + /// Changes Buttons in view to reflect that we are editing a modal, to help differentiate that we are not creating a modal. + private func editingMode() { + cancelButton.setTitle("Delete", for: .normal); + cancelButton.removeTarget(nil, action: #selector(cancelAction(_:)), for: .touchUpInside) + cancelButton.addTarget(self, action: #selector(deleteAction(_:)), for: .touchUpInside) + cancelButton.layer.borderWidth = 1.0 + cancelButton.layer.borderColor = CGColor(red:0,green:0,blue:0,alpha:1.0); + cancelButton.layer.backgroundColor = CGColor(red: 220/255.0, green: 53/255.0, blue: 69/255.0, alpha: 1.0) + cancelButton.setTitleColor(UIColor.white, for: .normal) + startNowButton.setTitle("Ok", for: .normal); + headerLabel.text = "Edit Blowby"; } - private func addListeners() { NotificationCenter.default.addObserver(self, selector: #selector(self.inputItemValueChanged(notification:)), name: .InputItemValueChanged, object: nil) @@ -82,11 +117,15 @@ class NewBlowbyModal: ModalView, Theme { @objc func inputItemValueChanged(notification: Notification) { guard let item: InputItem = notification.object as? InputItem else {return} // Set value in Realm object - self.newBlowBy.set(value: item.value.get(type: item.type) as Any, for: item.key) + if(editingBlowby){ + self.newBlowBy!.editSet(value: item.value.get(type: item.type) as Any, for: item.key) + } else { + self.newBlowBy!.set(value: item.value.get(type: item.type) as Any, for: item.key) + } } func generateInput(delegate: InputDelegate) { - let fields = newBlowBy.getThisBlowbyFields(editable: true, modalSize: true) + let fields = newBlowBy!.getThisBlowbyFields(editable: true, modalSize: true) self.inputGroup?.removeFromSuperview() let inputGroup: InputGroupView = InputGroupView() self.inputGroup = inputGroup From ccb5d2be9e56c57e1c24a8198d347f09ae4ec902 Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:55:32 -0800 Subject: [PATCH 13/17] Fixed duplications made during merge --- ipad/Models/Shift/ShiftModel.swift | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/ipad/Models/Shift/ShiftModel.swift b/ipad/Models/Shift/ShiftModel.swift index 90412b63..75e0c37c 100644 --- a/ipad/Models/Shift/ShiftModel.swift +++ b/ipad/Models/Shift/ShiftModel.swift @@ -34,7 +34,6 @@ class ShiftModel: Object, BaseRealmObject { @objc dynamic var k9OnShif: Bool = false @objc dynamic var motorizedBlowBys: Int = 0 @objc dynamic var nonMotorizedBlowBys: Int = 0 - @objc dynamic var k9OnShif: Bool = false @objc dynamic var station: String = "" @objc dynamic var shitStartComments: String = "" @objc dynamic var shitEndComments: String = "" @@ -107,22 +106,6 @@ class ShiftModel: Object, BaseRealmObject { } } - func addBlowby(blowby: BlowbyModel) -> BlowbyModel? { - blowby.shouldSync = true; - blowby.userId = self.userId; - do { - let realm = try Realm(); - try realm.write { - self.blowbys.append(blowby); - } - return blowby; - } catch let error as NSError { - print("** REALM ERROR"); - print(error); - return nil; - } - } - func addBlowby(blowby: BlowbyModel) -> BlowbyModel? { blowby.shouldSync = true; blowby.userId = self.userId; From 495ef0600f1c18a1f43847118cfbe30c3ea6d91c Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:04:36 -0800 Subject: [PATCH 14/17] Added recursive date functionality to Blowbys --- ipad/Models/Shift/ShiftModel.swift | 15 +++++++++++++++ ipad/Views/New Blowby Modal/NewBlowbyModal.swift | 1 + 2 files changed, 16 insertions(+) diff --git a/ipad/Models/Shift/ShiftModel.swift b/ipad/Models/Shift/ShiftModel.swift index 75e0c37c..906b0c3e 100644 --- a/ipad/Models/Shift/ShiftModel.swift +++ b/ipad/Models/Shift/ShiftModel.swift @@ -105,6 +105,20 @@ class ShiftModel: Object, BaseRealmObject { print(error) } } + func updateBlowbyTimeStamps(newDate: Date) { + do { + let realm = try Realm() + try realm.write { + for blowby in self.blowbys { + blowby.date = combineDateWithCurrentTime(targetDate: newDate, targetTime: blowby.date) + _ = blowby.formattedDateTime(time: blowby.timeStamp,date: blowby.date) + } + } + } catch let error as NSError { + print("** REALM ERROR") + print(error) + } + } func addBlowby(blowby: BlowbyModel) -> BlowbyModel? { blowby.shouldSync = true; @@ -139,6 +153,7 @@ class ShiftModel: Object, BaseRealmObject { self.formattedDate = shiftStartDate.stringShort() } updateInspectionTimeStamps(newDate: shiftStartDate); + updateBlowbyTimeStamps(newDate: shiftStartDate) } } catch let error as NSError { print("** REALM ERROR") diff --git a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift index bad9d2b9..ec096a02 100644 --- a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift +++ b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift @@ -85,6 +85,7 @@ class NewBlowbyModal: ModalView, Theme { //Give the modal a refernce to the current shift, and set the Blowby self.model = shift; self.newBlowBy = newBlowby; + self.newBlowBy!.date = self.model!.shiftStartDate; // since a valid modal would have a timeStamp passed in, we can determine if this is an empty model or an existing one self.editingBlowby = newBlowBy!.timeStamp != ""; if(self.editingBlowby) { From 3e6d1abc14c45328c71e7730dc97dbe2de225f1b Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:23:30 -0800 Subject: [PATCH 15/17] corrected date change causing crash --- ipad/Constants/AppRemoteAPIConst.swift | 10 +++++----- ipad/Views/New Blowby Modal/NewBlowbyModal.swift | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ipad/Constants/AppRemoteAPIConst.swift b/ipad/Constants/AppRemoteAPIConst.swift index 44e2a824..54c31956 100644 --- a/ipad/Constants/AppRemoteAPIConst.swift +++ b/ipad/Constants/AppRemoteAPIConst.swift @@ -32,11 +32,11 @@ enum RemoteEnv: String { case .local: return LOCAL_URL case .dev: - return DEV_URL + return LOCAL_URL case .test: - return TEST_URL + return LOCAL_URL case .prod: - return PROD_URL + return LOCAL_URL } } @@ -45,9 +45,9 @@ enum RemoteEnv: String { case .local,.dev: return KC_DEV_URL case .test: - return KC_TEST_URL + return KC_DEV_URL case .prod: - return KC_PROD_URL + return KC_DEV_URL } } } diff --git a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift index ec096a02..4ac760e3 100644 --- a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift +++ b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift @@ -85,11 +85,12 @@ class NewBlowbyModal: ModalView, Theme { //Give the modal a refernce to the current shift, and set the Blowby self.model = shift; self.newBlowBy = newBlowby; - self.newBlowBy!.date = self.model!.shiftStartDate; // since a valid modal would have a timeStamp passed in, we can determine if this is an empty model or an existing one self.editingBlowby = newBlowBy!.timeStamp != ""; if(self.editingBlowby) { editingMode(); + } else { + self.newBlowBy!.date = self.model!.shiftStartDate; } generateInput(delegate: delegate); addListeners(); From e644a8e73e4a7914fbcb6e2cc4c8236d08f3b2b6 Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:55:05 -0800 Subject: [PATCH 16/17] Accidental commit of URL changes --- ipad/Constants/AppRemoteAPIConst.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ipad/Constants/AppRemoteAPIConst.swift b/ipad/Constants/AppRemoteAPIConst.swift index 54c31956..44e2a824 100644 --- a/ipad/Constants/AppRemoteAPIConst.swift +++ b/ipad/Constants/AppRemoteAPIConst.swift @@ -32,11 +32,11 @@ enum RemoteEnv: String { case .local: return LOCAL_URL case .dev: - return LOCAL_URL + return DEV_URL case .test: - return LOCAL_URL + return TEST_URL case .prod: - return LOCAL_URL + return PROD_URL } } @@ -45,9 +45,9 @@ enum RemoteEnv: String { case .local,.dev: return KC_DEV_URL case .test: - return KC_DEV_URL + return KC_TEST_URL case .prod: - return KC_DEV_URL + return KC_PROD_URL } } } From 5bf9a894bfbe8213b0c863456fe7bf86678b3481 Mon Sep 17 00:00:00 2001 From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:44:59 -0800 Subject: [PATCH 17/17] Add documentation to new files and functions --- ipad/Models/Shift/BlowbyModel.swift | 13 +++++++------ .../Shift/Form Fields/ShiftFormHelper.swift | 19 +++++++++++++++++-- .../New Blowby Modal/NewBlowbyModal.swift | 4 ++-- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/ipad/Models/Shift/BlowbyModel.swift b/ipad/Models/Shift/BlowbyModel.swift index f84b0d5a..4b0b9614 100644 --- a/ipad/Models/Shift/BlowbyModel.swift +++ b/ipad/Models/Shift/BlowbyModel.swift @@ -2,8 +2,8 @@ // BlowbyModel.swift // ipad // -// Created by Matthew Logan on 2024-01-02. -// Copyright © 2024 Amir Shayegh. All rights reserved. +// Created by Sustainment Team on 2024-01-02. +// Copyright © Sustainment Team. All rights reserved. // import Foundation @@ -11,6 +11,7 @@ import Foundation import Realm import RealmSwift +/// Model for displaying Blowbys that occur during a shift, complies with Realm protocols class BlowbyModel: Object, BaseRealmObject { @objc dynamic var userId: String = "" @objc dynamic var localId: String = { @@ -95,11 +96,11 @@ class BlowbyModel: Object, BaseRealmObject { return BlowByFormHelper.getBlowByFields(for: self, editable: editable, modalSize: modalSize) } - /// <#Description#> + /// Creates a formatted Date time object for displaying Blowby Data /// - Parameters: - /// - time: <#time description#> - /// - date: <#date description#> - /// - Returns: <#description#> + /// - time: Value from the TimeInput field + /// - date: Value from the Date Input field + /// - Returns: Date object taking the calendar date from date object, and time value from time String func formattedDateTime(time: String, date: Date) -> String? { let timeFormatter = DateFormatter() timeFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss" diff --git a/ipad/Models/Shift/Form Fields/ShiftFormHelper.swift b/ipad/Models/Shift/Form Fields/ShiftFormHelper.swift index 6e71fd59..d2f4cb62 100644 --- a/ipad/Models/Shift/Form Fields/ShiftFormHelper.swift +++ b/ipad/Models/Shift/Form Fields/ShiftFormHelper.swift @@ -8,8 +8,16 @@ import Foundation + +/// Helper class for producing input fields for Shiftmodels class ShiftFormHelper { - + + /// Gets the required Input objects needed for the ShiftStartFields section of shift + /// - Parameters: + /// - object: Instance of the ShiftModel + /// - editable: Will forms be editable, or viewable only + /// - modalSize: Small rendering of components, or regular size rendering of components + /// - Returns: [InputItems] Form input items static func getShiftStartFields(for object: ShiftModel? = nil, editable: Bool? = true, modalSize: Bool? = false) -> [InputItem] { var sectionItems: [InputItem] = [] @@ -52,7 +60,11 @@ class ShiftFormHelper { return sectionItems } - + /// Gets the required Input objects needed for the ShiftEndFields section of shift + /// - Parameters: + /// - object: Instance of the ShiftModel + /// - editable: Will forms be editable, or viewable only + /// - Returns: [InputItems] Form input items static func getShiftEndFields(for object: ShiftModel? = nil, editable: Bool? = true) -> [InputItem] { var sectionItems: [InputItem] = [] @@ -94,6 +106,9 @@ class ShiftFormHelper { return sectionItems } + + /// Return the columns for displaying Shift Overview information + /// - Returns: [TableViewColumnConfig] Array of table column configuration objects func getTableColumns() -> [TableViewColumnConfig] { // Create Column Config var columns: [TableViewColumnConfig] = [] diff --git a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift index 4ac760e3..12281cf8 100644 --- a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift +++ b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift @@ -10,6 +10,7 @@ import Foundation import Modal import UIKit +/// Modal for displaying and editing Blowby information occuring in a shift class NewBlowbyModal: ModalView, Theme { // MARK: Variables @@ -82,7 +83,6 @@ class NewBlowbyModal: ModalView, Theme { present(); style(); - //Give the modal a refernce to the current shift, and set the Blowby self.model = shift; self.newBlowBy = newBlowby; // since a valid modal would have a timeStamp passed in, we can determine if this is an empty model or an existing one @@ -98,7 +98,7 @@ class NewBlowbyModal: ModalView, Theme { accessibilityValue = "newShiftModal"; } - /// Changes Buttons in view to reflect that we are editing a modal, to help differentiate that we are not creating a modal. + /// Changes Buttons and Headers in Modal to reflect we are editing a Blowby. private func editingMode() { cancelButton.setTitle("Delete", for: .normal); cancelButton.removeTarget(nil, action: #selector(cancelAction(_:)), for: .touchUpInside)