Skip to content

Commit

Permalink
Setup Views for Medication Tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
PSchmiedmayer committed Jan 28, 2024
1 parent 52e0d6e commit 198ec09
Show file tree
Hide file tree
Showing 18 changed files with 645 additions and 16 deletions.
2 changes: 2 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ let package = Package(
.library(name: "SpeziMedicationTracking", targets: ["SpeziMedicationTracking"])
],
dependencies: [
.package(url: "https://github.com/StanfordSpezi/SpeziFoundation", .upToNextMinor(from: "0.1.0")),
.package(url: "https://github.com/StanfordSpezi/Spezi", .upToNextMinor(from: "0.8.0")),
.package(url: "https://github.com/StanfordSpezi/SpeziViews", .upToNextMinor(from: "0.6.2"))
],
Expand Down Expand Up @@ -53,6 +54,7 @@ let package = Package(
dependencies: [
.target(name: "SpeziMedication"),
.product(name: "Spezi", package: "Spezi"),
.product(name: "SpeziFoundation", package: "SpeziFoundation"),
.product(name: "SpeziViews", package: "SpeziViews")
],
resources: [
Expand Down
30 changes: 30 additions & 0 deletions Sources/SpeziMedication/Models/LogEntry.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import Foundation


public struct LogEntry: Codable, Equatable {
public let scheduledTime: Date?
public var event: LogEntryEvent
public var date: Date
public var dosage: Double


public init(
scheduledTime: Date?,
event: LogEntryEvent,
date: Date,
dosage: Double
) {
self.scheduledTime = scheduledTime
self.event = event
self.date = date
self.dosage = dosage
}
}
22 changes: 22 additions & 0 deletions Sources/SpeziMedication/Models/LogEntryEvent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// File.swift
//
//
// Created by Paul Shmiedmayer on 1/28/24.
//


public enum LogEntryEvent: Codable {
case skipped
case taken


public var localizedDescription: String {
switch self {
case .skipped:
String(localized: "Skipped", bundle: .module)
case .taken:
String(localized: "Taken", bundle: .module)
}
}
}
2 changes: 2 additions & 0 deletions Sources/SpeziMedication/Models/MedicationInstance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public protocol MedicationInstance: Codable, Identifiable, Comparable, Hashable
var dosage: InstanceDosage { get set }
/// Schedule of the medication.
var schedule: Schedule { get set }
/// Log entries of the medication
var logEntries: [LogEntry] { get set }
}


Expand Down
6 changes: 6 additions & 0 deletions Sources/SpeziMedication/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
},
"Every other Day" : {

},
"Skipped" : {

},
"Taken" : {

},
"Weekend" : {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ extension MedicationSettingsViewModel {
preconditionFailure("If \(String(describing: Medications.self)) is a class type, it must conform to `Observable` using the `@Observable` macro.")
}

#warning(
"""
TODO: If Medications have an ID, we would always override all IDs when we replace the medications,
we might need to replace them step by step and modify the fileds of existing medications ...
"""
)
// If the medication instances are classes we need to make copies of them to ensure that we don't modify the original instances before the user presses save.
medicationInstances = Set(
self.medicationInstances.map { medicationInstance in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,7 @@ struct EditScheduleTimeRow: View {
)
.frame(width: 100)
Spacer()
TextField(
String(localized: "Quantity", bundle: .module),
value: $time.dosage,
formatter: numberOfDosageFormatter
)
.focused($dosageFieldIsFocused)
.textFieldStyle(.roundedBorder)
.keyboardType(.decimalPad)
.frame(maxWidth: 90)
dosageTextField
}
.background {
Color.clear
Expand All @@ -69,6 +61,31 @@ struct EditScheduleTimeRow: View {
}
}

private var dosageTextField: some View {
TextField(
String(localized: "Quantity", bundle: .module),
value: $time.dosage,
formatter: numberOfDosageFormatter
)
.focused($dosageFieldIsFocused)
.textFieldStyle(.roundedBorder)
.keyboardType(.decimalPad)
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button(
action: {
dosageFieldIsFocused = false
},
label: {
Text("Done")
}
)
}
}
.frame(maxWidth: 90)
}


init(time: Binding<ScheduledTime>, times: Binding<[ScheduledTime]>) {
self._time = time
Expand Down
46 changes: 46 additions & 0 deletions Sources/SpeziMedicationTracking/LogEntryEventButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SpeziMedication
import SwiftUI


struct LogEntryEventButton: View {
private let role: LogEntryEvent
@Binding private var logEntryEvent: LogEntryEvent?


var body: some View {
Button(
action: {
withAnimation {
if logEntryEvent != role {
logEntryEvent = role
} else {
logEntryEvent = nil
}
}
},
label: {
HStack {
if logEntryEvent == role {
Image(systemName: "checkmark.circle.fill")
.accessibilityHidden(true)
}
Text(role.localizedDescription)
}
}
)
}


init(role: LogEntryEvent, logEntryEvent: Binding<LogEntryEvent?>) {
self.role = role
self._logEntryEvent = logEntryEvent
}
}
70 changes: 70 additions & 0 deletions Sources/SpeziMedicationTracking/MedicationDosageAndDateSheet.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SpeziMedication
import SwiftUI


private let numberOfDosageFormatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter
}()


struct MedicationDosageAndDateSheet<MI: MedicationInstance>: View {
let medicationInstance: MI

@Environment(\.dismiss) var dismiss

@Binding private var logEntryDosage: Double
@Binding private var logEntryDate: Date


var body: some View {
NavigationStack {
HStack {
Text(medicationInstance.type.localizedDescription)
.bold()
Text(medicationInstance.dosage.localizedDescription)
.foregroundStyle(.secondary)
Form {
Section {
TextField(
"Dosage",
value: $logEntryDosage,
formatter: numberOfDosageFormatter
)
}
Section {
DatePicker(
"Time",
selection: $logEntryDate,
displayedComponents: .hourAndMinute
)
}
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button("Done") {
dismiss()
}
}
}
.navigationTitle("Log Details")
}
}


init(medicationInstance: MI, logEntryDosage: Binding<Double>, logEntryDate: Binding<Date>) {
self.medicationInstance = medicationInstance
self._logEntryDosage = logEntryDosage
self._logEntryDate = logEntryDate
}
}
21 changes: 21 additions & 0 deletions Sources/SpeziMedicationTracking/MedicationLogLoggedRow.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SpeziMedication
import SwiftUI


struct MedicationLogLoggedRow<MI: MedicationInstance>: View {
@Binding private var medicationInstances: [MI]
private var selectedDate: Date = .now


var body: some View {
Text("...")
}
}
60 changes: 60 additions & 0 deletions Sources/SpeziMedicationTracking/MedicationLogRow.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2022 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//

import SpeziMedication
import SwiftUI


struct MedicationLogRow<MI: MedicationInstance>: View {
private let medicationLogRowModel: MedicationLogRowModel<MI>

@State var presentMedicationLogSheet = false


var body: some View {
VStack {
HStack {
if let date = medicationLogRowModel.date {
Text(date, style: .time)
} else {
Text("As Needed Medications")
}
Spacer()
Image(systemName: "plus")
.accessibilityHidden(true)
.foregroundColor(.accentColor)
}
if medicationLogRowModel.date != nil {
ForEach(medicationLogRowModel.medications) { medicationInstance in
HStack {
Image(systemName: "pills.circle.fill")
.symbolRenderingMode(.hierarchical)
.accessibilityHidden(true)
Text(medicationInstance.wrappedValue.type.localizedDescription)
}
}
}
}
.background {
RoundedRectangle(cornerRadius: 5.0)
.foregroundColor(.accentColor.opacity(0.2))
}
.contentShape(Rectangle())
.onTapGesture {
presentMedicationLogSheet.toggle()
}
.sheet(isPresented: $presentMedicationLogSheet) {
MedicationLogSheet(medicationLogRowModel: medicationLogRowModel)
}
}


init(medicationLogRowModel: MedicationLogRowModel<MI>) {
self.medicationLogRowModel = medicationLogRowModel
}
}
Loading

0 comments on commit 198ec09

Please sign in to comment.