From 29346d886c32f6dd40398a13607ef17eff4fb0e9 Mon Sep 17 00:00:00 2001
From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com>
Date: Thu, 13 Jun 2024 09:00:48 -0700
Subject: [PATCH 1/8] Current State of Form Validation
---
ipad/Constants/AppRemoteAPIConst.swift | 2 +-
ipad/Models/Shift/ShiftModel.swift | 5 ++++
.../WatercraftInspectionModel.swift | 22 +++++++++-----
ipad/Services/ShiftService.swift | 12 ++++++++
ipad/Utilities/Status Color/StatusColor.swift | 2 ++
...ShiftBlowbysHeaderCollectionViewCell.swift | 4 ++-
...ShifOverviewHeaderCollectionViewCell.swift | 4 ++-
.../BlowbyTableCollectionViewCell.swift | 2 +-
.../InspectionsTableCollectionViewCell.swift | 2 +-
.../Shift/ShiftViewController.swift | 29 +++++++++++++++----
.../WatercraftInspectionViewController.swift | 10 +++++--
ipad/Views/Table/Table.swift | 2 ++
12 files changed, 74 insertions(+), 22 deletions(-)
diff --git a/ipad/Constants/AppRemoteAPIConst.swift b/ipad/Constants/AppRemoteAPIConst.swift
index 71d48571..b0c9abe6 100644
--- a/ipad/Constants/AppRemoteAPIConst.swift
+++ b/ipad/Constants/AppRemoteAPIConst.swift
@@ -57,7 +57,7 @@ class RemoteURLManager {
static var `default` = {
// Here We Can use Target Flag to customize
// Switch Env
- return RemoteURLManager(.dev)
+ return RemoteURLManager(.local)
}()
init(_ env: RemoteEnv) {
diff --git a/ipad/Models/Shift/ShiftModel.swift b/ipad/Models/Shift/ShiftModel.swift
index 475afa53..e1228261 100644
--- a/ipad/Models/Shift/ShiftModel.swift
+++ b/ipad/Models/Shift/ShiftModel.swift
@@ -15,6 +15,7 @@ enum SyncableItemStatus {
case Draft
case PendingSync
case Completed
+ case Errors
}
/// Represents a shift model for tracking inspection details and shift information.
@@ -184,6 +185,8 @@ class ShiftModel: Object, BaseRealmObject {
newStatus = "Pending Sync"
case .Completed:
newStatus = "Completed"
+ case .Errors:
+ newStatus = "Contains Errors"
}
do {
let realm = try Realm()
@@ -217,6 +220,8 @@ class ShiftModel: Object, BaseRealmObject {
return .PendingSync
case "completed":
return .Completed
+ case "contains errors":
+ return .Errors
default:
return .Draft
}
diff --git a/ipad/Models/Waterfract Inspection/WatercraftInspectionModel.swift b/ipad/Models/Waterfract Inspection/WatercraftInspectionModel.swift
index 468dc8b5..7df04e3c 100644
--- a/ipad/Models/Waterfract Inspection/WatercraftInspectionModel.swift
+++ b/ipad/Models/Waterfract Inspection/WatercraftInspectionModel.swift
@@ -12,6 +12,7 @@ import Realm
import RealmSwift
class WatercraftInspectionModel: Object, BaseRealmObject {
+ @objc dynamic var formDidValidate: Bool = false
@objc dynamic var userId: String = ""
@objc dynamic var localId: String = {
return UUID().uuidString
@@ -190,18 +191,19 @@ class WatercraftInspectionModel: Object, BaseRealmObject {
}
func set(shouldSync should: Bool) {
- set(status: should ? .PendingSync : .Draft )
+ if (formDidValidate) {
do {
- let realm = try Realm()
- try realm.write {
- self.shouldSync = should
- self.status = should ? "Pending Sync" : "Draft"
- }
+ let realm = try Realm()
+ try realm.write {
+ self.shouldSync = should
+ self.status = should ? "Pending Sync" : "Draft"
+ }
} catch let error as NSError {
- print("** REALM ERROR")
- print(error)
+ print("** REALM ERROR")
+ print(error)
}
set(status: should ? .PendingSync : .Draft )
+ }
}
func set(status statusEnum: SyncableItemStatus) {
@@ -213,6 +215,8 @@ class WatercraftInspectionModel: Object, BaseRealmObject {
newStatus = "Pending Sync"
case .Completed:
newStatus = "Completed"
+ case .Errors:
+ newStatus = "Not Validated"
}
do {
let realm = try Realm()
@@ -270,6 +274,8 @@ class WatercraftInspectionModel: Object, BaseRealmObject {
return .PendingSync
case "completed":
return .Completed
+ case "not validated":
+ return .Errors
default:
return .Draft
}
diff --git a/ipad/Services/ShiftService.swift b/ipad/Services/ShiftService.swift
index 200716a8..c9b0605e 100644
--- a/ipad/Services/ShiftService.swift
+++ b/ipad/Services/ShiftService.swift
@@ -68,6 +68,18 @@ class ShiftService {
/// - then: A closure that gets called once the shift has been submitted. It receives a boolean indicating whether the operation was successful.
public func submit(shift: ShiftModel, then: @escaping (_ success: Bool) -> Void) {
let shiftLocalId = shift.localId
+ if(!shift.inspections.allSatisfy(){item in return item.formDidValidate}) {
+ shift.set(shouldSync: false)
+ shift.set(status: .Errors)
+ shift.inspections.forEach(){inspection in
+ if (!inspection.formDidValidate){
+ inspection.set(shouldSync: false)
+ inspection.set(status: .Errors)
+ }
+ }
+ Alert.show(title: "Submission Error", message: "A shift contains non-validated inspections, please re-visit inspections and correct outstanding issues")
+ return then(false);
+ }
// Post call
post(shift: shift) { (shiftId) in
guard let remoteId = shiftId, let refetchedShift = Storage.shared.shift(withLocalId: shiftLocalId) else {
diff --git a/ipad/Utilities/Status Color/StatusColor.swift b/ipad/Utilities/Status Color/StatusColor.swift
index a621e510..57fadde0 100644
--- a/ipad/Utilities/Status Color/StatusColor.swift
+++ b/ipad/Utilities/Status Color/StatusColor.swift
@@ -18,6 +18,8 @@ class StatusColor {
return Colors.Status.Yellow
case "completed":
return Colors.Status.Green
+ case "contains errors", "not validated":
+ return Colors.Status.Red
default:
return Colors.Status.LightGray
}
diff --git a/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.swift
index 4804b2e9..981c9d5a 100644
--- a/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.swift
+++ b/ipad/ViewControllers/Shift/Cells/Blowbys/ShiftBlowbysHeaderCollectionViewCell.swift
@@ -17,7 +17,7 @@ class ShiftBlowBysHeaderCollectionViewCell: BaseShiftOverviewCollectionViewCell
override func autofill() {
guard let model = self.model else {return}
- if model.getStatus() != .Draft {
+ if [.Draft, .Errors].contains(model.getStatus()) {
addBlowByButton.alpha = 0
addBlowByButton.isEnabled = false
}
@@ -49,6 +49,8 @@ class ShiftBlowBysHeaderCollectionViewCell: BaseShiftOverviewCollectionViewCell
return Colors.Status.Green
case .Draft:
return Colors.Status.DarkGray
+ case .Errors:
+ return Colors.Status.Red
}
}
}
diff --git a/ipad/ViewControllers/Shift/Cells/Header/ShifOverviewHeaderCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Header/ShifOverviewHeaderCollectionViewCell.swift
index 4a53f8d9..384b4fce 100644
--- a/ipad/ViewControllers/Shift/Cells/Header/ShifOverviewHeaderCollectionViewCell.swift
+++ b/ipad/ViewControllers/Shift/Cells/Header/ShifOverviewHeaderCollectionViewCell.swift
@@ -26,7 +26,7 @@ class ShifOverviewHeaderCollectionViewCell: BaseShiftOverviewCollectionViewCell
self.locationLabel.text = model.station
self.statusLabel.text = model.status
self.statusIndicator.backgroundColor = StatusColor.color(for: model.status)
- if model.getStatus() != .Draft {
+ if ![.Draft, .Errors].contains(model.getStatus()) {
addInspectionButton.alpha = 0
addInspectionButton.isEnabled = false
}
@@ -65,6 +65,8 @@ class ShifOverviewHeaderCollectionViewCell: BaseShiftOverviewCollectionViewCell
return Colors.Status.Green
case .Draft:
return Colors.Status.DarkGray
+ case .Errors:
+ return Colors.Status.Red
}
}
}
diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
index dc8c1b2f..31a47c67 100644
--- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
+++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
@@ -59,7 +59,7 @@ class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell {
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 {
+ if model.getStatus() != .Draft && model.getStatus() != .Errors {
columns.removeLast()
blowByButton.alpha = 0
blowByButton.isEnabled = false
diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/InspectionsTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/InspectionsTableCollectionViewCell.swift
index c6caeab8..9317324c 100644
--- a/ipad/ViewControllers/Shift/Cells/Inspections/InspectionsTableCollectionViewCell.swift
+++ b/ipad/ViewControllers/Shift/Cells/Inspections/InspectionsTableCollectionViewCell.swift
@@ -47,7 +47,7 @@ class InspectionsTableCollectionViewCell: BaseShiftOverviewCollectionViewCell {
tableHeightConstraint.constant = InspectionsTableCollectionViewCell.getTableHeight(for: model)
var buttonName = "View"
- if model.getStatus() == .Draft {
+ if [.Draft, .Errors].contains(model.getStatus()) {
buttonName = "Edit"
}
diff --git a/ipad/ViewControllers/Shift/ShiftViewController.swift b/ipad/ViewControllers/Shift/ShiftViewController.swift
index b06eab64..b6da1166 100644
--- a/ipad/ViewControllers/Shift/ShiftViewController.swift
+++ b/ipad/ViewControllers/Shift/ShiftViewController.swift
@@ -71,11 +71,28 @@ class ShiftViewController: BaseViewController {
}
override func viewWillAppear(_ animated: Bool) {
+ self.updateStatuses();
setupCollectionView()
self.collectionView.reloadData()
addListeners()
}
-
+ /// Iterates through inspections checking formDidValidate. If any for
+ private func updateStatuses() {
+ if(self.model!.status != "Completed"){
+ if (self.model!.inspections.allSatisfy(){$0.formDidValidate}){
+ self.model!.set(status: .Draft)
+ } else {
+ self.model!.set(status: .Draft)
+ self.model!.inspections.forEach{ inspection in
+ if(inspection.formDidValidate){
+ inspection.set(status: .Draft);
+ } else {
+ inspection.set(status: .Errors);
+ }
+ }
+ }
+ }
+ }
private func addListeners() {
NotificationCenter.default.removeObserver(self, name: .TableButtonClicked, object: nil)
NotificationCenter.default.removeObserver(self, name: .InputItemValueChanged, object: nil)
@@ -96,7 +113,7 @@ class ShiftViewController: BaseViewController {
blowbyModal.initialize(shift: currentShiftModel, delegate: self, onStart: { [weak self] (model) in
guard self != nil else { return }
}) {
- // Canceled
+ // Cancelled
}
}
@@ -107,7 +124,7 @@ class ShiftViewController: BaseViewController {
func setup(model: ShiftModel) {
self.model = model
- self.isEditable = model.getStatus() == .Draft || model.getStatus() == .PendingSync
+ self.isEditable = [.Draft, .PendingSync, .Errors].contains(model.getStatus())
if model.getStatus() == .PendingSync {
model.set(shouldSync: false)
for inspection in model.inspections {
@@ -116,8 +133,8 @@ class ShiftViewController: BaseViewController {
Alert.show(title: "Changed to draft", message: "Status changed to draft. tap submit when you've made your changes.")
}
- if model.getStatus() == .Draft {
- // make sure inspections are editable.
+ if [.Draft, .Errors].contains(model.getStatus()) {
+ // make sure inspections are editable.
for inspection in model.inspections {
inspection.set(shouldSync: false)
}
@@ -253,7 +270,7 @@ class ShiftViewController: BaseViewController {
navigation.navigationBar.tintColor = .white
navigation.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
setGradiantBackground(navigationBar: navigation.navigationBar)
- if let model = self.model, model.getStatus() == .Draft {
+ if let model = self.model, [.Draft, .Errors].contains(model.getStatus()) {
setRightNavButtons()
}
}
diff --git a/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift b/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
index 8d524d4e..5fc907f2 100644
--- a/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
+++ b/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
@@ -95,7 +95,7 @@ class WatercraftInspectionViewController: BaseViewController {
// MARK: Setup
func setup(model: WatercraftInspectionModel) {
self.model = model
- self.isEditable = model.getStatus() == .Draft
+ self.isEditable = [.Draft, .Errors].contains(model.getStatus())
self.styleNavBar()
if !model.isPassportHolder || model.launchedOutsideBC || model.isNewPassportIssued {
self.showFullInspection = true
@@ -169,7 +169,7 @@ class WatercraftInspectionViewController: BaseViewController {
navigation.navigationBar.tintColor = .white
navigation.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]
setGradiantBackground(navigationBar: navigation.navigationBar)
- if let model = self.model, model.getStatus() == .Draft {
+ if let model = self.model, [.Draft, .Errors].contains(model.getStatus()) {
setRightNavButtons()
setLeftNavButtons()
}
@@ -698,7 +698,11 @@ class WatercraftInspectionViewController: BaseViewController {
message += "\n"
}
}
-
+ model.set(value: message == "", for: "formDidValidate")
+ if (message == "") {
+ model.set(status: .Draft)
+ }
+
return message
}
diff --git a/ipad/Views/Table/Table.swift b/ipad/Views/Table/Table.swift
index d5e21994..ab9ab608 100644
--- a/ipad/Views/Table/Table.swift
+++ b/ipad/Views/Table/Table.swift
@@ -105,6 +105,8 @@ class Table {
return Colors.Status.Green
case "draft":
return Colors.Status.DarkGray
+ case "contains errors", "not validated":
+ return Colors.Status.Red
default:
return Colors.Status.DarkGray
}
From 99ccfbe20aa65a132d4d457ab549a79309911ee7 Mon Sep 17 00:00:00 2001
From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com>
Date: Thu, 13 Jun 2024 14:17:04 -0700
Subject: [PATCH 2/8] Convert empty string checks to native property "isEmpty".
simplify status flow. convert status check for consistency
---
.../BlowbyTableCollectionViewCell.swift | 2 +-
.../Shift/ShiftViewController.swift | 16 ++++++----------
.../WatercraftInspectionViewController.swift | 6 +++---
ipad/Views/Form/Input Cells/InputItem.swift | 2 +-
ipad/Views/Input Modal/InputModal.swift | 2 +-
.../Major Cities Picker/MajorCityPicker.swift | 10 +++++-----
ipad/Views/New Blowby Modal/NewBlowbyModal.swift | 4 ++--
ipadTests/testShift.swift | 4 ++--
8 files changed, 21 insertions(+), 25 deletions(-)
diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
index 31a47c67..c6630abc 100644
--- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
+++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
@@ -59,7 +59,7 @@ class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell {
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 && model.getStatus() != .Errors {
+ if [.Draft, .Errors].contains(model.getStatus()) {
columns.removeLast()
blowByButton.alpha = 0
blowByButton.isEnabled = false
diff --git a/ipad/ViewControllers/Shift/ShiftViewController.swift b/ipad/ViewControllers/Shift/ShiftViewController.swift
index b6da1166..667ad367 100644
--- a/ipad/ViewControllers/Shift/ShiftViewController.swift
+++ b/ipad/ViewControllers/Shift/ShiftViewController.swift
@@ -76,7 +76,7 @@ class ShiftViewController: BaseViewController {
self.collectionView.reloadData()
addListeners()
}
- /// Iterates through inspections checking formDidValidate. If any for
+ /// Iterates through inspections checking formDidValidate. If any form does validate, modifies all appropraite statuses to `.Errors`
private func updateStatuses() {
if(self.model!.status != "Completed"){
if (self.model!.inspections.allSatisfy(){$0.formDidValidate}){
@@ -84,11 +84,7 @@ class ShiftViewController: BaseViewController {
} else {
self.model!.set(status: .Draft)
self.model!.inspections.forEach{ inspection in
- if(inspection.formDidValidate){
- inspection.set(status: .Draft);
- } else {
- inspection.set(status: .Errors);
- }
+ inspection.set(status: inspection.formDidValidate ? .Draft : .Errors)
}
}
}
@@ -285,19 +281,19 @@ class ShiftViewController: BaseViewController {
// MARK: Validation
func canSubmit() -> Bool {
- return validationMessage() == ""
+ return validationMessage().isEmpty
}
func validationMessage() -> String {
var message: String = ""
guard let model = self.model else { return message }
var counter = 1
- if model.startTime == "" {
+ if model.startTime.isEmpty {
message = "\(message)\n\(counter)- Missing Shift Start time."
counter += 1
}
- if model.endTime == "" {
+ if model.endTime.isEmpty {
message = "\(message)\n\(counter)- Missing Shift End time."
counter += 1
}
@@ -323,7 +319,7 @@ class ShiftViewController: BaseViewController {
}
for inspection in model.inspections {
- if inspection.inspectionTime == "" {
+ if inspection.inspectionTime.isEmpty {
message = "\(message)\n\(counter)- Missing Time of Inspection."
counter += 1
}
diff --git a/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift b/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
index 5fc907f2..33328f52 100644
--- a/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
+++ b/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
@@ -243,7 +243,7 @@ class WatercraftInspectionViewController: BaseViewController {
}
func canSubmit() -> Bool {
- return validationMessage() == ""
+ return validationMessage().isEmpty
}
/// Enum error cases grouped by sections for clarity
@@ -698,8 +698,8 @@ class WatercraftInspectionViewController: BaseViewController {
message += "\n"
}
}
- model.set(value: message == "", for: "formDidValidate")
- if (message == "") {
+ model.set(value: message.isEmpty, for: "formDidValidate")
+ if (message.isEmpty) {
model.set(status: .Draft)
}
diff --git a/ipad/Views/Form/Input Cells/InputItem.swift b/ipad/Views/Form/Input Cells/InputItem.swift
index 27f9fec8..705a23f9 100644
--- a/ipad/Views/Form/Input Cells/InputItem.swift
+++ b/ipad/Views/Form/Input Cells/InputItem.swift
@@ -561,7 +561,7 @@ class TimeInput: InputItem {
func getValue() -> Time? {
let stringValue: String = self.value.get(type: self.type) as? String ?? ""
- if stringValue == "" {return nil}
+ if stringValue.isEmpty {return nil}
return Time(string: stringValue)
}
diff --git a/ipad/Views/Input Modal/InputModal.swift b/ipad/Views/Input Modal/InputModal.swift
index 481e59dd..64f0c89e 100644
--- a/ipad/Views/Input Modal/InputModal.swift
+++ b/ipad/Views/Input Modal/InputModal.swift
@@ -66,7 +66,7 @@ class InputModal: ModalView, Theme {
}
func validateInput(text: String) -> Bool {
- if text.removeWhitespaces() == "" {
+ if text.removeWhitespaces().isEmpty {
invalidInput(message: "Please enter a value")
return false
} else {
diff --git a/ipad/Views/Major Cities Picker/MajorCityPicker.swift b/ipad/Views/Major Cities Picker/MajorCityPicker.swift
index 73dc3de0..5e1c6c36 100644
--- a/ipad/Views/Major Cities Picker/MajorCityPicker.swift
+++ b/ipad/Views/Major Cities Picker/MajorCityPicker.swift
@@ -94,7 +94,7 @@ class MajorCityPicker: UIView, Theme {
self.searchBar.delegate = self
self.tableView.reloadData()
self.selectionsHeightConstraint.constant = 0
- self.selectButton.isEnabled = !(self.selection.display == "")
+ self.selectButton.isEnabled = !(self.selection.display.isEmpty)
searchBar.isAccessibilityElement = true
searchBar.accessibilityLabel = "search-majorcities"
searchBar.accessibilityValue = "search-majorcities"
@@ -142,12 +142,12 @@ class MajorCityPicker: UIView, Theme {
}
private func showOrHideSelectionsIfNeeded() {
- let selectTitle = !(self.selection.display == "") ? "Select (1)" : "Select"
+ let selectTitle = !(self.selection.display.isEmpty) ? "Select (1)" : "Select"
self.selectButton.setTitle(selectTitle, for: .normal)
- self.selectButton.isEnabled = !(self.selection.display == "")
+ self.selectButton.isEnabled = !(self.selection.display.isEmpty)
UIView.animate(withDuration: 0.3) {
- self.selectionsHeightConstraint.constant = !(self.selection.display == "") ? 60 : 0
- self.collectionView.alpha = !(self.selection.display == "") ? 1 : 0
+ self.selectionsHeightConstraint.constant = !(self.selection.display.isEmpty) ? 60 : 0
+ self.collectionView.alpha = !(self.selection.display.isEmpty) ? 1 : 0
self.layoutIfNeeded()
}
}
diff --git a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift
index 12281cf8..eccbb1bc 100644
--- a/ipad/Views/New Blowby Modal/NewBlowbyModal.swift
+++ b/ipad/Views/New Blowby Modal/NewBlowbyModal.swift
@@ -57,10 +57,10 @@ class NewBlowbyModal: ModalView, Theme {
// If (Valid) Add Blowby, remove and return
var invalidFields: [String] = []
- if newBlowBy!.timeStamp == "" {
+ if newBlowBy!.timeStamp.isEmpty {
invalidFields.append("Blowby Time")
}
- if newBlowBy!.watercraftComplexity == "" {
+ if newBlowBy!.watercraftComplexity.isEmpty {
invalidFields.append("Watercraft Complexity")
}
if !invalidFields.isEmpty {
diff --git a/ipadTests/testShift.swift b/ipadTests/testShift.swift
index 434a09d2..9c13904a 100644
--- a/ipadTests/testShift.swift
+++ b/ipadTests/testShift.swift
@@ -59,7 +59,7 @@ class testShift: XCTestCase {
vc.setup(model: shiftModel)
shiftModel.inspections.append(createTestInspection())
shiftModel.boatsInspected = false
- XCTAssert(vc.canSubmit() == false && (shiftModel.startTime == "" || shiftModel.endTime == ""))
+ XCTAssert(vc.canSubmit() == false && (shiftModel.startTime.isEmpty || shiftModel.endTime.isEmpty))
}
func testValidShiftForSubmission() {
@@ -70,7 +70,7 @@ class testShift: XCTestCase {
shiftModel.endTime = "18:00"
shiftModel.inspections.append(createTestInspection())
shiftModel.boatsInspected = true
- XCTAssert(vc.canSubmit() == true && (shiftModel.startTime != "" || shiftModel.endTime != ""))
+ XCTAssert(vc.canSubmit() == true && (shiftModel.startTime.isEmpty || !shiftModel.endTime.isEmpty))
}
}
From d70c2942fba0820046324508b8812c6c6f2234c8 Mon Sep 17 00:00:00 2001
From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com>
Date: Thu, 13 Jun 2024 14:59:26 -0700
Subject: [PATCH 3/8] Correct conditional causing blowby button to not appear,
set target to dev realm
---
ipad/Constants/AppRemoteAPIConst.swift | 2 +-
.../Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ipad/Constants/AppRemoteAPIConst.swift b/ipad/Constants/AppRemoteAPIConst.swift
index b0c9abe6..71d48571 100644
--- a/ipad/Constants/AppRemoteAPIConst.swift
+++ b/ipad/Constants/AppRemoteAPIConst.swift
@@ -57,7 +57,7 @@ class RemoteURLManager {
static var `default` = {
// Here We Can use Target Flag to customize
// Switch Env
- return RemoteURLManager(.local)
+ return RemoteURLManager(.dev)
}()
init(_ env: RemoteEnv) {
diff --git a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
index c6630abc..ed75a5a3 100644
--- a/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
+++ b/ipad/ViewControllers/Shift/Cells/Inspections/BlowbyTableCollectionViewCell.swift
@@ -59,7 +59,7 @@ class BlowbyTableCollectionViewCell: BaseShiftOverviewCollectionViewCell {
columns.append(TableViewColumnConfig(key: "", header: "Edit", type: .Button, buttonName: "Edit", showHeader: false))
// Disable adding blowbys if not completed and hide delete button
- if [.Draft, .Errors].contains(model.getStatus()) {
+ if ![.Draft, .Errors].contains(model.getStatus()) {
columns.removeLast()
blowByButton.alpha = 0
blowByButton.isEnabled = false
From c9c8d3d3b3c279c852a63e656485226e1d61adaf Mon Sep 17 00:00:00 2001
From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com>
Date: Thu, 13 Jun 2024 15:13:31 -0700
Subject: [PATCH 4/8] When form is opened, set formDidValidate to false
---
.../WatercraftInspectionViewController.swift | 1 +
1 file changed, 1 insertion(+)
diff --git a/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift b/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
index 33328f52..5e4490f9 100644
--- a/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
+++ b/ipad/ViewControllers/Watercraft Inspections/WatercraftInspectionViewController.swift
@@ -94,6 +94,7 @@ class WatercraftInspectionViewController: BaseViewController {
// MARK: Setup
func setup(model: WatercraftInspectionModel) {
+ model.set(value: false, for: "formDidValidate")
self.model = model
self.isEditable = [.Draft, .Errors].contains(model.getStatus())
self.styleNavBar()
From d520884bdfa0d9cda98f1514871d1bbbdb94680d Mon Sep 17 00:00:00 2001
From: LocalNewsTV <62873746+LocalNewsTV@users.noreply.github.com>
Date: Fri, 14 Jun 2024 07:22:04 -0700
Subject: [PATCH 5/8] Lint, add information about XCode 15 and Realm
---
README.md | 143 ++++++++++++++++++++++++++++++++----------------------
1 file changed, 85 insertions(+), 58 deletions(-)
diff --git a/README.md b/README.md
index 1c3839c5..b8433563 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# Inspect
+
[![img](https://img.shields.io/badge/Lifecycle-Maturing-007EC6)](https://github.com/bcgov/repomountie/blob/master/doc/lifecycle-badges.md)
This application is for the field-based recording of watercraft inspections for Zebra and Quagga Mussels in British Columbia, Canada.
@@ -6,43 +7,53 @@ This application is for the field-based recording of watercraft inspections for
# Setup
Before you begin, install [Cocoapods](https://cocoapods.org) on your machine if you don't have it yet.
+
```
sudo gem install cocoapods
```
-Once you have installed the dependency manager, follow the setup instructions below.
-1) Clone [this](https://github.com/bcgov/invasivesBC-mussels-iOS) repo:
+Once you have installed the dependency manager, follow the setup instructions below.
+
+1. Clone [this](https://github.com/bcgov/invasivesBC-mussels-iOS) repo:
+
```
git clone https://github.com/bcgov/invasivesBC-mussels-iOS
```
-2) Navigate to project folder:
+
+2. Navigate to project folder:
+
```
cd invasivesBC-mussels-iOS
```
-3) Install Pods/Dependencies:
+
+3. Install Pods/Dependencies:
+
```
pod install
```
-4) Open `ipad.xcworkspace` to open the project in Xcode.
+
+4. Open `ipad.xcworkspace` to open the project in Xcode.
+
```
open ipad.xcworkspace
```
-*Note: Always use `ipad.xcworkspace` to open this project.*
+_Note: Always use `ipad.xcworkspace` to open this project._
5. In [AppRemoteAPIConst](ipad/Constants/AppRemoteAPIConst.swift), change the enum in `RemoteURLManager` to `.local`
+
```swift
class RemoteURLManager {
var env: RemoteEnv = .dev
static var `default` = {
// Here We Can use Target Flag to customize
- // Switch Env
+ // Switch Env
return RemoteURLManager(.local) // <--- change from .prod to .local
// change BACK to .prod when pushing to master
}()
```
-*Note: do not push this change to* `master` *or to the App Store; use* `.dev` *for local testing, and push only for testing on TestFlight - more on this [below](#setting-up-a-testflight-build-for-dev)*
+_Note: do not push this change to_ `master` _or to the App Store; use_ `.dev` _for local testing, and push only for testing on TestFlight - more on this [below](#setting-up-a-testflight-build-for-dev)_
You may need to also update the Signing & Capabilities to be able to run the application. More information in the [Provisioning Profile](#provisioning-profile-and-certificate) below as well.
@@ -57,11 +68,26 @@ Any local changes to a [Realm](https://realm.io/realm-swift/) model will require
```
You can increment the build in
-
+
**ipad > General > Identity.**
+The increasing build number will persist across all your branches. Realm objects persist in the iOS device, and aren't limited to just the application.
+
+> [!NOTE]
+> If the data stored on your simulator is of no value to you, you can also reset your Simulator by doing the following steps
+
+1. selecting `Device` from the menu options
+2. `Erase all Content and Settings`
+3. Confirm your decision
+
## Simulator
+### XCode version 15 or higher
+
+The application is in a state where it supports Apple silicon devices. Users can simply use an iPad simulator of their preference to start the application
+
+### XCode version 14 or lower
+
You can run the app through the Simulator from Xcode. Ensure that the Simulator is also running with Rosetta active - this can be done by going to:
**Product > Destination > Destination Architectures > Show Rosetta Destinations**
@@ -71,6 +97,7 @@ Ensure that you’re running the simulator on **iPad (10th generation) (Rosetta)
## Roles
Anyone with an `IDIR` can log into the application, but only users with the following roles can create and submit entries.
+
- `inspectAppOfficer`
- `inspectAppAdmin`
- `admin`
@@ -78,18 +105,19 @@ Anyone with an `IDIR` can log into the application, but only users with the foll
Roles are requested through the Inspect team or the [Sustainment Team](mailto:sustainment.team@gov.bc.ca).
The Inspect and Sustainment team provision roles through the [Common Hosted Single Sign-on (CSS) Dashboard](https://bcgov.github.io/sso-requests/my-dashboard/integrations). To assign a user a role, go to the dashboard and follow these steps:
-1) Login with your IDIR to the [CSS Dashboard](https://bcgov.github.io/sso-requests/my-dashboard/integrations).
-2) Select **InspectBC Mussels**
-3) In **INTEGRATION DETAILS**, select the **Assign Users to Roles** tab.
-4) Under **Search for a user based on the selection criteria below**, select the realm for the user: **Dev**, **Test**, or **Prod**.
- *Note: a local build will use the **Dev** realm for roles.*
+1. Login with your IDIR to the [CSS Dashboard](https://bcgov.github.io/sso-requests/my-dashboard/integrations).
+2. Select **InspectBC Mussels**
+3. In **INTEGRATION DETAILS**, select the **Assign Users to Roles** tab.
+4. Under **Search for a user based on the selection criteria below**, select the realm for the user: **Dev**, **Test**, or **Prod**.
-5) Search for user by **First Name**, **Last Name**, or **Email**. Select that user from the table.
+ _Note: a local build will use the **Dev** realm for roles._
- If you can't find a user with the search functionality above, there is a button to **Search in IDIM Web Service Lookup** to add the user. After adding the user with the download button, search for them again and they should appear in the table.
+5. Search for user by **First Name**, **Last Name**, or **Email**. Select that user from the table.
-6) Under **Assign User to a Role**, select any of the roles listed above (e.g. `inspectAppOfficer`).
+ If you can't find a user with the search functionality above, there is a button to **Search in IDIM Web Service Lookup** to add the user. After adding the user with the download button, search for them again and they should appear in the table.
+
+6. Under **Assign User to a Role**, select any of the roles listed above (e.g. `inspectAppOfficer`).
**[More information about creating roles in the CSS Dashboard can be found here.](https://mvp.developer.gov.bc.ca/docs/default/component/css-docs/Creating-a-Role/)**
@@ -97,7 +125,6 @@ The Inspect and Sustainment team provision roles through the [Common Hosted Sing
You should be able to access [App Store Connect](https://appstoreconnect.apple.com/) using your BC Government email as the Apple ID login. If you're not already part of the Inspect group on App Store Connect, request an invite from [Sustainment Team](mailto:sustainment.team@gov.bc.ca). More information about adding users to App Store Connect can be found in [Apple's documentation here](https://developer.apple.com/help/account/manage-your-team/invite-team-members/).
-
## Building the App
All changes merged into the `master` branch will automatically create a new build in App Store Connect using [GitHub Actions](.github/workflows/main.yaml). This will also create a new build for testing in TestFlight. More information about [TestFlight below](#testflight-app).
@@ -110,9 +137,9 @@ If planning on releasing a new version of the app, you will need to i
**as well as in the GitHub Action** in [`main.yaml`](https://github.com/bcgov/invasivesBC-mussels-iOS/blob/master/.github/workflows/main.yaml). This is the `APP_BUILD_VERSION` env.
-*Note: We use standard semantic versioning for the app in App Store Connect (`Major.Minor.Patch`)*
+_Note: We use standard semantic versioning for the app in App Store Connect (`Major.Minor.Patch`)_
-You will not need to increment the **build** number when pushing to `master` as that is done automatically through GitHub Actions with each push. Do not push your local build increments.
+You will not need to increment the **build** number when pushing to `master` as that is done automatically through GitHub Actions with each push. Do not push your local build increments.
## TestFlight and User Testing
@@ -124,7 +151,7 @@ Testers can be added in [App Store Connect](https://appstoreconnect.apple.com/)
This dashboard will show you all the available builds on the current or newest version of the app, as well as any testers. You can select the "+" beside **Testers** to send an invite to new testers.
-A user will receive an email saying **Government of British Columbia has invited you to test Inspect** and have a button that says *View in TestFlight*. This will allow the user to open the app in TestFlight.
+A user will receive an email saying **Government of British Columbia has invited you to test Inspect** and have a button that says _View in TestFlight_. This will allow the user to open the app in TestFlight.
If a user opens TestFlight and sees a "Redeem code" prompt, they might need to find that email and open the app in TestFlight again, or you may need to remove the user from the **Testers** group in App Store Connect and re-invite them.
@@ -134,7 +161,7 @@ Test users will be notified by email of any new builds in TestFlight, as any new
Note that the Inspect app can only be tested on an iPad through the [TestFlight app on the App Store](https://apps.apple.com/ca/app/testflight/id899247664) as the Inspect app is for iPads only.
-A new build in TestFlight will send an email with the subject like: *Inspect 2.7 (401) for iOS is now available to test* and will have a link to open the new version in the TestFlight app.
+A new build in TestFlight will send an email with the subject like: _Inspect 2.7 (401) for iOS is now available to test_ and will have a link to open the new version in the TestFlight app.
### Setting up a TestFlight Build for Dev
@@ -147,55 +174,53 @@ class RemoteURLManager {
var env: RemoteEnv = .dev
static var `default` = {
// Here We Can use Target Flag to customize
- // Switch Env
+ // Switch Env
return RemoteURLManager(.dev) // <--- change to .dev for testing
// change BACK to .prod afterwards
}()
```
-Please ensure that if you're pushing builds with a `.dev` extension to TestFlight, you explicitly mention them in the PR. This is to avoid mistakenly deploying these changes to the App Store when the application is configured to use the **Dev** realm.
+Please ensure that if you're pushing builds with a `.dev` extension to TestFlight, you explicitly mention them in the PR. This is to avoid mistakenly deploying these changes to the App Store when the application is configured to use the **Dev** realm.
-Therefore, once users have completed and approved the changes from the `.dev` build in TestFlight, you will need to make *another** PR against `master` where `RemoteUrlManager` has been set *back* to `.prod`. This can be tested again by Testers if you like, but this will be the production database so no data should be saved. This version and build can be added for review to be published to the App Store.
+Therefore, once users have completed and approved the changes from the `.dev` build in TestFlight, you will need to make *another\*\* PR against `master` where `RemoteUrlManager` has been set *back\* to `.prod`. This can be tested again by Testers if you like, but this will be the production database so no data should be saved. This version and build can be added for review to be published to the App Store.
## Deploying the App
Once you've fully tested the app on TestFlight, you are now ready to deploy the app to the App Store.
1. **Make sure the app is set to look at** `.prod`**!**
-2. Login to [App Store Connect](https://appstoreconnect.apple.com/) and select **My Apps** and choose **Inspect**.
-3. Navigate to the **App Store** tab.
+2. Login to [App Store Connect](https://appstoreconnect.apple.com/) and select **My Apps** and choose **Inspect**.
+3. Navigate to the **App Store** tab.
4. Select the "**+**" button beside iOS App to increment the next version of the app.
-5. Type the next version number and Select **Create**.
+5. Type the next version number and Select **Create**.
6. Update the **What’s New in This Version** text box with the changes outlined in the PR(s).
7. Scroll to **Build** and select the "**+**" button.
-8. Choose the build you want to add and select **Next**. It should show the newly added build.
+8. Choose the build you want to add and select **Next**. It should show the newly added build.
9. Scroll to the App Review Information section.
-
- Because there’s not an IDIR for the Apple Testing team to use to review the app, we record a screen capture of the app (clicking all buttons, scrolling through the app, etc.) for the current version. We then attach the video for Apple to review, or upload it to [Google Drive](https://drive.google.com/drive/home) and share the link in the App Review Information section. You'll need to provide a short explanation of the recording.
-
- Feel free to use the template below:
-
- ```
- Here are a few notes of the screen recording:
- - The videos are screen recordings of an iOS device (iPad Pro 12.9-inch 6th generation) running the app.
- - The screen recordings were captured using xCode's Simulator's screen recording.
- - The app was running locally using a local database.
- - I attempted to interact with every button and form field that was available to the user beyond the login screen (the login was completed automatically as I has signed in earlier)
-
- General notes:
- - The application is to be used by research scientists, BC Government Conservation officers and external partners and sister agencies.
- - This app uses a government identification system to authenticate users.
- ```
-
- You can record your screen in the xCode Simulator through **File** > **Record Screen**
-
-
-10. Scroll to **Version Release** and select **Manually release this version** if you want to release the version at your own discretion after the app is approved, otherwise you can select to **Automatically release the version as soon as it is approved by the Apple Review team**.
+
+ Because there’s not an IDIR for the Apple Testing team to use to review the app, we record a screen capture of the app (clicking all buttons, scrolling through the app, etc.) for the current version. We then attach the video for Apple to review, or upload it to [Google Drive](https://drive.google.com/drive/home) and share the link in the App Review Information section. You'll need to provide a short explanation of the recording.
+
+ Feel free to use the template below:
+
+ ```
+ Here are a few notes of the screen recording:
+ - The videos are screen recordings of an iOS device (iPad Pro 12.9-inch 6th generation) running the app.
+ - The screen recordings were captured using xCode's Simulator's screen recording.
+ - The app was running locally using a local database.
+ - I attempted to interact with every button and form field that was available to the user beyond the login screen (the login was completed automatically as I has signed in earlier)
+
+ General notes:
+ - The application is to be used by research scientists, BC Government Conservation officers and external partners and sister agencies.
+ - This app uses a government identification system to authenticate users.
+ ```
+
+ You can record your screen in the xCode Simulator through **File** > **Record Screen**
+
+10. Scroll to **Version Release** and select **Manually release this version** if you want to release the version at your own discretion after the app is approved, otherwise you can select to **Automatically release the version as soon as it is approved by the Apple Review team**.
11. Select **Add for Review**.
12. Once that’s added for review, you then need to select **Submit to App Review** to send the version to the App Store review team.
-
-Once it’s successfully submitted, you should be given a confirmation screen with a Submission ID. On average, submitted app reviews should only take a few hours before being approved, although Apple indicates it can take up to 24 hours for a response.
+Once it’s successfully submitted, you should be given a confirmation screen with a Submission ID. On average, submitted app reviews should only take a few hours before being approved, although Apple indicates it can take up to 24 hours for a response.
## Provisioning Profile and Certificate
@@ -203,9 +228,9 @@ GitHub Actions will sign the app using BCGov's provisioning profile, which is is
#### Add Provisioning Profile to Xcode
-Once you receive the provisioning profile, you can drag-and-drop it to Xcode, where it will then appear under *ipad* > *Signing & Capabilities* > *iOS* > *Provisioning Profile***. Select the new Provisioning Profile in Xcode.
+Once you receive the provisioning profile, you can drag-and-drop it to Xcode, where it will then appear under _ipad_ > _Signing & Capabilities_ > _iOS_ > \*Provisioning Profile\*\*\*. Select the new Provisioning Profile in Xcode.
-***Note: the `Status` in Xcode may show "no signing certificate", and that's because the Certificate is supplied by the BCGov Organization in the repo's [GitHub Actions secrets and variables](https://github.com/bcgov/invasivesBC-mussels-iOS/settings/secrets/actions).*
+_\*\*Note: the `Status` in Xcode may show "no signing certificate", and that's because the Certificate is supplied by the BCGov Organization in the repo's [GitHub Actions secrets and variables](https://github.com/bcgov/invasivesBC-mussels-iOS/settings/secrets/actions)._
#### Add Provisioning Profile to the Repo's Secrets and Variables
@@ -224,13 +249,16 @@ You'll also need to update the strings for the provisioning **name** and **UUID*
And replace the values in the `.plist` files.
`options.plist`:
+
```plist
ca.bc.gov.InvasivesBC
bb2b59b7-03d0-4b86-8d8a-c1b827bf923f
```
+
`exportOptions.plist`:
+
```plist exportOptions.plist
ca.bc.gov.InvasivesBC
@@ -238,12 +266,10 @@ And replace the values in the `.plist` files.
```
-
-(The provisioning **name** should be what appears in Xcode under *ipad* > *Signing & Capabilities* > *iOS* > *Provisioning Profile*.)
+(The provisioning **name** should be what appears in Xcode under _ipad_ > _Signing & Capabilities_ > _iOS_ > _Provisioning Profile_.)
[**The Developer Experience team has more information on GitHub Actions and deploying to App Store Connect here**](https://mvp.developer.gov.bc.ca/docs/default/component/mobile-developer-guide/apple_app_signing/).
-
# Workflows
- Login ![Login](https://github.com/bcgov/invasivesBC-mussels-iOS/blob/master/Workflow-login.jpg)
@@ -252,17 +278,18 @@ And replace the values in the `.plist` files.
- Inspection ![Inspection](https://github.com/bcgov/invasivesBC-mussels-iOS/blob/master/Workflow-inspection.jpg)
# [Forms](https://github.com/bcgov/invasivesBC-mussels-iOS/tree/master/ipad/Views/Form)
+
The forms in the app are created with the help of a framework created for this application called [`InputGroupView`](https://github.com/bcgov/invasivesBC-mussels-iOS/tree/master/ipad/Views/Form) which allows us to create and edit the forms quickly and directly from the code.
- Fields for the Watercraft Inspection form are defined [here](https://github.com/bcgov/invasivesBC-mussels-iOS/tree/master/ipad/Models/Waterfract%20Inspection/Form%20Fields).
- Fields for the shift form are defined [here](https://github.com/bcgov/invasivesBC-mussels-iOS/tree/master/ipad/Models/Shift/Form%20Fields).
These files have functions that return the fields for each section of the forms. here you can:
+
- change the placement of the fields by changing the order in which the fields are created or by changing the function (section) that the fields are included in.
- change the type of field that's displayed by changing a single line of code.
- change the width size of each field by changing the width value.
-
This framework also allows you to change the look of all fields of a certain type, for example text fields, by changing a single `.xib` file.
[There are many time-saving advantages to using this framework in an agile environment and you can find more details about this framework here](https://github.com/bcgov/invasivesBC-mussels-iOS/tree/master/ipad/Views/Form)
From 08b180bb1705e113ec762cbd1a1b538e3cd35c0c Mon Sep 17 00:00:00 2001
From: PaulGarewal
Date: Mon, 9 Dec 2024 11:03:15 -0800
Subject: [PATCH 6/8] feat: added touch ups to validation tracking and error
status - Add formDidValidate to prevent submission of unvalidated inspection
at restart - renamed water craft inspection folder - optimized
updateStatuses() function - removed print statement in viewWillDisappear
function
---
ipad.xcodeproj/project.pbxproj | 4 +-
.../DestinationWaterBodyModel.swift | 0
.../Form Fields/HighRiskFormHelper.swift | 0
.../WatercraftInspectionFormHelper.swift | 0
.../HighRiskAssessmentModel.swift | 0
.../MajorCityModel.swift | 0
.../PreviousWaterBodyModel.swift | 0
.../WatercraftInspectionModel.swift | 30 ++++++++-------
.../Shift/ShiftViewController.swift | 38 +++++++++++++------
9 files changed, 45 insertions(+), 27 deletions(-)
rename ipad/Models/{Waterfract Inspection => Watercraft Inspection}/DestinationWaterBodyModel.swift (100%)
rename ipad/Models/{Waterfract Inspection => Watercraft Inspection}/Form Fields/HighRiskFormHelper.swift (100%)
rename ipad/Models/{Waterfract Inspection => Watercraft Inspection}/Form Fields/WatercraftInspectionFormHelper.swift (100%)
rename ipad/Models/{Waterfract Inspection => Watercraft Inspection}/HighRiskAssessmentModel.swift (100%)
rename ipad/Models/{Waterfract Inspection => Watercraft Inspection}/MajorCityModel.swift (100%)
rename ipad/Models/{Waterfract Inspection => Watercraft Inspection}/PreviousWaterBodyModel.swift (100%)
rename ipad/Models/{Waterfract Inspection => Watercraft Inspection}/WatercraftInspectionModel.swift (97%)
diff --git a/ipad.xcodeproj/project.pbxproj b/ipad.xcodeproj/project.pbxproj
index b7dd6f40..9b1acff6 100644
--- a/ipad.xcodeproj/project.pbxproj
+++ b/ipad.xcodeproj/project.pbxproj
@@ -601,7 +601,7 @@
path = Shift;
sourceTree = "";
};
- 2944BCD62433929700826F48 /* Waterfract Inspection */ = {
+ 2944BCD62433929700826F48 /* Watercraft Inspection */ = {
isa = PBXGroup;
children = (
294D9A872379C62F00BD4928 /* WatercraftInspectionModel.swift */,
@@ -611,7 +611,7 @@
298BF7CD2395D57E0072AA28 /* DestinationWaterBodyModel.swift */,
2944BCD8243392F600826F48 /* Form Fields */,
);
- path = "Waterfract Inspection";
+ path = "Watercraft Inspection";
sourceTree = "";
};
2944BCD8243392F600826F48 /* Form Fields */ = {
diff --git a/ipad/Models/Waterfract Inspection/DestinationWaterBodyModel.swift b/ipad/Models/Watercraft Inspection/DestinationWaterBodyModel.swift
similarity index 100%
rename from ipad/Models/Waterfract Inspection/DestinationWaterBodyModel.swift
rename to ipad/Models/Watercraft Inspection/DestinationWaterBodyModel.swift
diff --git a/ipad/Models/Waterfract Inspection/Form Fields/HighRiskFormHelper.swift b/ipad/Models/Watercraft Inspection/Form Fields/HighRiskFormHelper.swift
similarity index 100%
rename from ipad/Models/Waterfract Inspection/Form Fields/HighRiskFormHelper.swift
rename to ipad/Models/Watercraft Inspection/Form Fields/HighRiskFormHelper.swift
diff --git a/ipad/Models/Waterfract Inspection/Form Fields/WatercraftInspectionFormHelper.swift b/ipad/Models/Watercraft Inspection/Form Fields/WatercraftInspectionFormHelper.swift
similarity index 100%
rename from ipad/Models/Waterfract Inspection/Form Fields/WatercraftInspectionFormHelper.swift
rename to ipad/Models/Watercraft Inspection/Form Fields/WatercraftInspectionFormHelper.swift
diff --git a/ipad/Models/Waterfract Inspection/HighRiskAssessmentModel.swift b/ipad/Models/Watercraft Inspection/HighRiskAssessmentModel.swift
similarity index 100%
rename from ipad/Models/Waterfract Inspection/HighRiskAssessmentModel.swift
rename to ipad/Models/Watercraft Inspection/HighRiskAssessmentModel.swift
diff --git a/ipad/Models/Waterfract Inspection/MajorCityModel.swift b/ipad/Models/Watercraft Inspection/MajorCityModel.swift
similarity index 100%
rename from ipad/Models/Waterfract Inspection/MajorCityModel.swift
rename to ipad/Models/Watercraft Inspection/MajorCityModel.swift
diff --git a/ipad/Models/Waterfract Inspection/PreviousWaterBodyModel.swift b/ipad/Models/Watercraft Inspection/PreviousWaterBodyModel.swift
similarity index 100%
rename from ipad/Models/Waterfract Inspection/PreviousWaterBodyModel.swift
rename to ipad/Models/Watercraft Inspection/PreviousWaterBodyModel.swift
diff --git a/ipad/Models/Waterfract Inspection/WatercraftInspectionModel.swift b/ipad/Models/Watercraft Inspection/WatercraftInspectionModel.swift
similarity index 97%
rename from ipad/Models/Waterfract Inspection/WatercraftInspectionModel.swift
rename to ipad/Models/Watercraft Inspection/WatercraftInspectionModel.swift
index 7df04e3c..3b2cf294 100644
--- a/ipad/Models/Waterfract Inspection/WatercraftInspectionModel.swift
+++ b/ipad/Models/Watercraft Inspection/WatercraftInspectionModel.swift
@@ -191,28 +191,30 @@ class WatercraftInspectionModel: Object, BaseRealmObject {
}
func set(shouldSync should: Bool) {
- if (formDidValidate) {
- do {
- let realm = try Realm()
- try realm.write {
- self.shouldSync = should
- self.status = should ? "Pending Sync" : "Draft"
- }
- } catch let error as NSError {
- print("** REALM ERROR")
- print(error)
+ if (formDidValidate) {
+ do {
+ let realm = try Realm()
+ try realm.write {
+ self.shouldSync = should
+ self.status = should ? "Pending Sync" : "Draft"
+ }
+ } catch let error as NSError {
+ print("** REALM ERROR")
+ print(error)
+ }
+ } else {
+ // If form isn't validated, force status to Errors
+ set(status: .Errors)
}
- set(status: should ? .PendingSync : .Draft )
- }
}
func set(status statusEnum: SyncableItemStatus) {
var newStatus = "\(statusEnum)"
switch statusEnum {
case .Draft:
- newStatus = "Draft"
+ newStatus = formDidValidate ? "Draft" : "Not Validated"
case .PendingSync:
- newStatus = "Pending Sync"
+ newStatus = formDidValidate ? "Pending Sync" : "Not Validated"
case .Completed:
newStatus = "Completed"
case .Errors:
diff --git a/ipad/ViewControllers/Shift/ShiftViewController.swift b/ipad/ViewControllers/Shift/ShiftViewController.swift
index 667ad367..bc9f571c 100644
--- a/ipad/ViewControllers/Shift/ShiftViewController.swift
+++ b/ipad/ViewControllers/Shift/ShiftViewController.swift
@@ -66,7 +66,6 @@ class ShiftViewController: BaseViewController {
}
override func viewWillDisappear(_ animated: Bool) {
- print(self)
NotificationCenter.default.removeObserver(self)
}
@@ -78,16 +77,20 @@ class ShiftViewController: BaseViewController {
}
/// Iterates through inspections checking formDidValidate. If any form does validate, modifies all appropraite statuses to `.Errors`
private func updateStatuses() {
- if(self.model!.status != "Completed"){
- if (self.model!.inspections.allSatisfy(){$0.formDidValidate}){
- self.model!.set(status: .Draft)
- } else {
- self.model!.set(status: .Draft)
- self.model!.inspections.forEach{ inspection in
- inspection.set(status: inspection.formDidValidate ? .Draft : .Errors)
- }
+ guard let model = self.model else { return }
+ if(model.status != "Completed"){
+ if (model.inspections.allSatisfy(){$0.formDidValidate}){
+ model.set(status: .Draft)
+ model.inspections.forEach { inspection in
+ inspection.set(status: .Draft)
+ }
+ } else {
+ model.set(status: .Errors)
+ model.inspections.forEach { inspection in
+ inspection.set(status: inspection.formDidValidate ? .Draft : .Errors)
+ }
+ }
}
- }
}
private func addListeners() {
NotificationCenter.default.removeObserver(self, name: .TableButtonClicked, object: nil)
@@ -190,12 +193,14 @@ class ShiftViewController: BaseViewController {
@objc func completeAction(sender: UIBarButtonItem) {
guard let model = self.model else { return }
self.dismissKeyboard()
+
+ self.updateStatuses()
// if can submit
var alertMessage = "This shift and the inspections will be uploaded when possible"
if model.shiftStartDate < Calendar.current.startOfDay(for: Date()) {
alertMessage += "\n\n You've entered a date that occurred before today. If this was intentional, no problem! Otherwise, please double-check the entered date: \n\(model.shiftStartDate.stringShort())"
}
- if canSubmit() {
+ if canSubmit() && model.inspections.allSatisfy({ $0.formDidValidate }) {
Alert.show(title: "Are you sure?", message: alertMessage, yes: {[weak self] in
guard let strongSelf = self else { return }
model.set(shouldSync: true)
@@ -356,6 +361,17 @@ class ShiftViewController: BaseViewController {
}
}
}
+
+ // Check for invalid inspections
+ let invalidInspections = model.inspections.filter { !$0.formDidValidate }
+ if !invalidInspections.isEmpty {
+ message = "\(message)\n\(counter)- One or more inspections contain validation errors. Please review each inspection."
+ counter += 1
+ }
+
+ if !message.isEmpty {
+ model.set(status: .Errors)
+ }
return message
}
From 7f83c08e9829d26f339290408322c7202c81baa8 Mon Sep 17 00:00:00 2001
From: PaulGarewal
Date: Mon, 9 Dec 2024 16:14:21 -0800
Subject: [PATCH 7/8] small change to build file
---
ipad.xcodeproj/project.pbxproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ipad.xcodeproj/project.pbxproj b/ipad.xcodeproj/project.pbxproj
index 9b1acff6..15e09ee9 100644
--- a/ipad.xcodeproj/project.pbxproj
+++ b/ipad.xcodeproj/project.pbxproj
@@ -547,7 +547,7 @@
isa = PBXGroup;
children = (
2944BCD52433928400826F48 /* Shift */,
- 2944BCD62433929700826F48 /* Waterfract Inspection */,
+ 2944BCD62433929700826F48 /* Watercraft Inspection */,
2933DD60238DC5120068E9DF /* CodeTableModel.swift */,
298BF7C7239590730072AA28 /* WaterBodyTableModel.swift */,
29FEA09F23FF12C200F490DB /* UserRoleModel.swift */,
From 305ce170c65aeb508cf8b8f1f95c5c0a6489256e Mon Sep 17 00:00:00 2001
From: PaulGarewal
Date: Mon, 9 Dec 2024 16:26:16 -0800
Subject: [PATCH 8/8] build version increment to keep track of features in
separate builds
---
.github/workflows/main.yaml | 2 +-
ipad.xcodeproj/project.pbxproj | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml
index 55701401..c4122bff 100644
--- a/.github/workflows/main.yaml
+++ b/.github/workflows/main.yaml
@@ -15,7 +15,7 @@ jobs:
ARCHIVE_NAME: ${{ 'invasivesbc-mussels.iOS.xcarchive' }}
EXPORT_DIR: ${{ 'export' }}
IPA_NAME: ${{ 'invasivesbc-mussels.iOS.ipa' }}
- APP_BUILD_VERSION: "2.7.2"
+ APP_BUILD_VERSION: "2.7.3"
steps:
- uses: maxim-lobanov/setup-xcode@v1
diff --git a/ipad.xcodeproj/project.pbxproj b/ipad.xcodeproj/project.pbxproj
index 15e09ee9..c956d394 100644
--- a/ipad.xcodeproj/project.pbxproj
+++ b/ipad.xcodeproj/project.pbxproj
@@ -2059,7 +2059,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 2.8.3;
+ MARKETING_VERSION = 2.8.4;
PRODUCT_BUNDLE_IDENTIFIER = ca.bc.gov.InvasivesBC;
PRODUCT_NAME = Inspect;
PROVISIONING_PROFILE_SPECIFIER = "InvasivesBC Muscles - 2023/24";
@@ -2089,7 +2089,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 2.8.3;
+ MARKETING_VERSION = 2.8.4;
PRODUCT_BUNDLE_IDENTIFIER = ca.bc.gov.InvasivesBC;
PRODUCT_NAME = Inspect;
PROVISIONING_PROFILE_SPECIFIER = "InvasivesBC Muscles - 2023/24";