Implement dose tracking functionality and enhance CSV migration
- Added a new migration script to introduce dose tracking columns in the CSV. - Updated DataManager to handle new dose tracking columns and methods for adding doses. - Enhanced MedTrackerApp to support dose entry and display for each medicine. - Modified UIManager to create a scrollable input frame with dose tracking elements. - Implemented tests for delete functionality, dose tracking, edit functionality, and scrollable input. - Updated existing tests to ensure compatibility with the new CSV format and dose tracking features.
This commit is contained in:
+122
-15
@@ -26,9 +26,13 @@ class DataManager:
|
||||
"sleep",
|
||||
"appetite",
|
||||
"bupropion",
|
||||
"bupropion_doses",
|
||||
"hydroxyzine",
|
||||
"hydroxyzine_doses",
|
||||
"gabapentin",
|
||||
"gabapentin_doses",
|
||||
"propranolol",
|
||||
"propranolol_doses",
|
||||
"note",
|
||||
]
|
||||
)
|
||||
@@ -48,9 +52,13 @@ class DataManager:
|
||||
"sleep": int,
|
||||
"appetite": int,
|
||||
"bupropion": int,
|
||||
"bupropion_doses": str,
|
||||
"hydroxyzine": int,
|
||||
"hydroxyzine_doses": str,
|
||||
"gabapentin": int,
|
||||
"gabapentin_doses": str,
|
||||
"propranolol": int,
|
||||
"propranolol_doses": str,
|
||||
"note": str,
|
||||
"date": str,
|
||||
},
|
||||
@@ -96,21 +104,45 @@ class DataManager:
|
||||
return False
|
||||
|
||||
# Find the row to update using original_date as a unique identifier
|
||||
df.loc[
|
||||
df["date"] == original_date,
|
||||
[
|
||||
"date",
|
||||
"depression",
|
||||
"anxiety",
|
||||
"sleep",
|
||||
"appetite",
|
||||
"bupropion",
|
||||
"hydroxyzine",
|
||||
"gabapentin",
|
||||
"propranolol",
|
||||
"note",
|
||||
],
|
||||
] = values
|
||||
# Handle both old format (10 columns) and new format (14 columns)
|
||||
if len(values) == 14:
|
||||
# New format with dose columns
|
||||
df.loc[
|
||||
df["date"] == original_date,
|
||||
[
|
||||
"date",
|
||||
"depression",
|
||||
"anxiety",
|
||||
"sleep",
|
||||
"appetite",
|
||||
"bupropion",
|
||||
"bupropion_doses",
|
||||
"hydroxyzine",
|
||||
"hydroxyzine_doses",
|
||||
"gabapentin",
|
||||
"gabapentin_doses",
|
||||
"propranolol",
|
||||
"propranolol_doses",
|
||||
"note",
|
||||
],
|
||||
] = values
|
||||
else:
|
||||
# Old format - only update the user-editable columns
|
||||
df.loc[
|
||||
df["date"] == original_date,
|
||||
[
|
||||
"date",
|
||||
"depression",
|
||||
"anxiety",
|
||||
"sleep",
|
||||
"appetite",
|
||||
"bupropion",
|
||||
"hydroxyzine",
|
||||
"gabapentin",
|
||||
"propranolol",
|
||||
"note",
|
||||
],
|
||||
] = values
|
||||
df.to_csv(self.filename, index=False)
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -129,3 +161,78 @@ class DataManager:
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error deleting entry: {str(e)}")
|
||||
return False
|
||||
|
||||
def add_medicine_dose(self, date: str, medicine_name: str, dose: str) -> bool:
|
||||
"""Add a medicine dose to today's entry."""
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
df: pd.DataFrame = self.load_data()
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
dose_entry = f"{timestamp}:{dose}"
|
||||
|
||||
# Find or create entry for the given date
|
||||
if df.empty or date not in df["date"].values:
|
||||
# Create new entry for today with default values
|
||||
new_entry = {
|
||||
"date": date,
|
||||
"depression": 0,
|
||||
"anxiety": 0,
|
||||
"sleep": 0,
|
||||
"appetite": 0,
|
||||
"bupropion": 0,
|
||||
"bupropion_doses": "",
|
||||
"hydroxyzine": 0,
|
||||
"hydroxyzine_doses": "",
|
||||
"gabapentin": 0,
|
||||
"gabapentin_doses": "",
|
||||
"propranolol": 0,
|
||||
"propranolol_doses": "",
|
||||
"note": "",
|
||||
}
|
||||
df = pd.concat([df, pd.DataFrame([new_entry])], ignore_index=True)
|
||||
|
||||
# Add dose to the appropriate medicine
|
||||
dose_column = f"{medicine_name}_doses"
|
||||
mask = df["date"] == date
|
||||
current_doses = df.loc[mask, dose_column].iloc[0]
|
||||
|
||||
if current_doses:
|
||||
df.loc[mask, dose_column] = current_doses + "|" + dose_entry
|
||||
else:
|
||||
df.loc[mask, dose_column] = dose_entry
|
||||
|
||||
# Mark medicine as taken (set to 1)
|
||||
df.loc[mask, medicine_name] = 1
|
||||
|
||||
df.to_csv(self.filename, index=False)
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error adding medicine dose: {str(e)}")
|
||||
return False
|
||||
|
||||
def get_today_medicine_doses(
|
||||
self, date: str, medicine_name: str
|
||||
) -> list[tuple[str, str]]:
|
||||
"""Get list of (timestamp, dose) tuples for a medicine on a given date."""
|
||||
try:
|
||||
df: pd.DataFrame = self.load_data()
|
||||
if df.empty or date not in df["date"].values:
|
||||
return []
|
||||
|
||||
dose_column = f"{medicine_name}_doses"
|
||||
doses_str = df.loc[df["date"] == date, dose_column].iloc[0]
|
||||
|
||||
if not doses_str:
|
||||
return []
|
||||
|
||||
doses = []
|
||||
for dose_entry in doses_str.split("|"):
|
||||
if ":" in dose_entry:
|
||||
timestamp, dose = dose_entry.split(":", 1)
|
||||
doses.append((timestamp, dose))
|
||||
|
||||
return doses
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting medicine doses: {str(e)}")
|
||||
return []
|
||||
|
||||
+167
-6
@@ -80,12 +80,16 @@ class MedTrackerApp:
|
||||
input_ui: dict[str, Any] = self.ui_manager.create_input_frame(main_frame)
|
||||
self.input_frame: ttk.Frame = input_ui["frame"]
|
||||
self.symptom_vars: dict[str, tk.IntVar] = input_ui["symptom_vars"]
|
||||
self.medicine_vars: dict[str, list[tk.IntVar | ttk.Spinbox]] = input_ui[
|
||||
"medicine_vars"
|
||||
]
|
||||
self.medicine_vars: dict[str, tuple[tk.IntVar, str]] = input_ui["medicine_vars"]
|
||||
self.dose_buttons: dict[str, ttk.Button] = input_ui["dose_buttons"]
|
||||
self.dose_entries: dict[str, ttk.Entry] = input_ui["dose_entries"]
|
||||
self.dose_displays: dict[str, tk.Text] = input_ui["dose_displays"]
|
||||
self.note_var: tk.StringVar = input_ui["note_var"]
|
||||
self.date_var: tk.StringVar = input_ui["date_var"]
|
||||
|
||||
# Set up dose button callbacks
|
||||
self._setup_dose_button_callbacks()
|
||||
|
||||
# Add buttons to input frame
|
||||
self.ui_manager.add_buttons(
|
||||
self.input_frame,
|
||||
@@ -108,6 +112,75 @@ class MedTrackerApp:
|
||||
# Load data
|
||||
self.load_data()
|
||||
|
||||
def _setup_dose_button_callbacks(self) -> None:
|
||||
"""Set up callbacks for dose tracking buttons."""
|
||||
for medicine_name, button in self.dose_buttons.items():
|
||||
button.config(
|
||||
command=lambda med=medicine_name: self._take_medicine_dose(med)
|
||||
)
|
||||
|
||||
# Update dose displays for today
|
||||
self._update_dose_displays()
|
||||
|
||||
def _take_medicine_dose(self, medicine_name: str) -> None:
|
||||
"""Record a dose of medicine taken right now."""
|
||||
dose_entry = self.dose_entries[medicine_name]
|
||||
dose = dose_entry.get().strip()
|
||||
|
||||
if not dose:
|
||||
messagebox.showerror(
|
||||
"Error",
|
||||
f"Please enter a dose amount for {medicine_name}",
|
||||
parent=self.root,
|
||||
)
|
||||
return
|
||||
|
||||
# Use today's date
|
||||
today = self.date_var.get()
|
||||
if not today:
|
||||
from datetime import datetime
|
||||
|
||||
today = datetime.now().strftime("%m/%d/%Y")
|
||||
self.date_var.set(today)
|
||||
|
||||
if self.data_manager.add_medicine_dose(today, medicine_name, dose):
|
||||
messagebox.showinfo(
|
||||
"Success",
|
||||
f"{medicine_name.title()} dose recorded: {dose}",
|
||||
parent=self.root,
|
||||
)
|
||||
# Clear dose entry
|
||||
dose_entry.delete(0, tk.END)
|
||||
# Update displays and reload data
|
||||
self._update_dose_displays()
|
||||
self.load_data()
|
||||
else:
|
||||
messagebox.showerror(
|
||||
"Error", f"Failed to record {medicine_name} dose", parent=self.root
|
||||
)
|
||||
|
||||
def _update_dose_displays(self) -> None:
|
||||
"""Update the dose display areas with today's doses."""
|
||||
today = self.date_var.get()
|
||||
if not today:
|
||||
return
|
||||
|
||||
for medicine_name, display in self.dose_displays.items():
|
||||
doses = self.data_manager.get_today_medicine_doses(today, medicine_name)
|
||||
|
||||
display.config(state=tk.NORMAL)
|
||||
display.delete(1.0, tk.END)
|
||||
|
||||
if doses:
|
||||
dose_text = "\n".join(
|
||||
[f"{timestamp}: {dose}" for timestamp, dose in doses]
|
||||
)
|
||||
display.insert(1.0, dose_text)
|
||||
else:
|
||||
display.insert(1.0, "No doses recorded today")
|
||||
|
||||
display.config(state=tk.DISABLED)
|
||||
|
||||
def on_double_click(self, event: tk.Event) -> None:
|
||||
"""Handle double-click event to edit an entry."""
|
||||
logger.debug("Double-click event triggered on treeview.")
|
||||
@@ -146,6 +219,34 @@ class MedTrackerApp:
|
||||
note: str,
|
||||
) -> None:
|
||||
"""Save the edited data to the CSV file."""
|
||||
# Get existing dose data for this date to preserve it
|
||||
bup_doses = ""
|
||||
hydro_doses = ""
|
||||
gaba_doses = ""
|
||||
prop_doses = ""
|
||||
|
||||
# Try to get existing dose data
|
||||
try:
|
||||
existing_bup = self.data_manager.get_today_medicine_doses(
|
||||
original_date, "bupropion"
|
||||
)
|
||||
existing_hydro = self.data_manager.get_today_medicine_doses(
|
||||
original_date, "hydroxyzine"
|
||||
)
|
||||
existing_gaba = self.data_manager.get_today_medicine_doses(
|
||||
original_date, "gabapentin"
|
||||
)
|
||||
existing_prop = self.data_manager.get_today_medicine_doses(
|
||||
original_date, "propranolol"
|
||||
)
|
||||
|
||||
bup_doses = "|".join([f"{ts}:{dose}" for ts, dose in existing_bup])
|
||||
hydro_doses = "|".join([f"{ts}:{dose}" for ts, dose in existing_hydro])
|
||||
gaba_doses = "|".join([f"{ts}:{dose}" for ts, dose in existing_gaba])
|
||||
prop_doses = "|".join([f"{ts}:{dose}" for ts, dose in existing_prop])
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not retrieve existing dose data: {e}")
|
||||
|
||||
values: list[str | int] = [
|
||||
date,
|
||||
dep,
|
||||
@@ -153,9 +254,13 @@ class MedTrackerApp:
|
||||
slp,
|
||||
app,
|
||||
bup,
|
||||
bup_doses,
|
||||
hydro,
|
||||
hydro_doses,
|
||||
gaba,
|
||||
gaba_doses,
|
||||
prop,
|
||||
prop_doses,
|
||||
note,
|
||||
]
|
||||
|
||||
@@ -188,6 +293,30 @@ class MedTrackerApp:
|
||||
|
||||
def add_entry(self) -> None:
|
||||
"""Add a new entry to the CSV file."""
|
||||
# Get current doses for today
|
||||
today = self.date_var.get()
|
||||
bupropion_doses = ""
|
||||
hydroxyzine_doses = ""
|
||||
gabapentin_doses = ""
|
||||
propranolol_doses = ""
|
||||
|
||||
if today:
|
||||
bup_doses = self.data_manager.get_today_medicine_doses(today, "bupropion")
|
||||
hydroxyzine_doses_list = self.data_manager.get_today_medicine_doses(
|
||||
today, "hydroxyzine"
|
||||
)
|
||||
gaba_doses = self.data_manager.get_today_medicine_doses(today, "gabapentin")
|
||||
prop_doses = self.data_manager.get_today_medicine_doses(
|
||||
today, "propranolol"
|
||||
)
|
||||
|
||||
bupropion_doses = "|".join([f"{ts}:{dose}" for ts, dose in bup_doses])
|
||||
hydroxyzine_doses = "|".join(
|
||||
[f"{ts}:{dose}" for ts, dose in hydroxyzine_doses_list]
|
||||
)
|
||||
gabapentin_doses = "|".join([f"{ts}:{dose}" for ts, dose in gaba_doses])
|
||||
propranolol_doses = "|".join([f"{ts}:{dose}" for ts, dose in prop_doses])
|
||||
|
||||
entry: list[str | int] = [
|
||||
self.date_var.get(),
|
||||
self.symptom_vars["depression"].get(),
|
||||
@@ -195,9 +324,13 @@ class MedTrackerApp:
|
||||
self.symptom_vars["sleep"].get(),
|
||||
self.symptom_vars["appetite"].get(),
|
||||
self.medicine_vars["bupropion"][0].get(),
|
||||
bupropion_doses,
|
||||
self.medicine_vars["hydroxyzine"][0].get(),
|
||||
hydroxyzine_doses,
|
||||
self.medicine_vars["gabapentin"][0].get(),
|
||||
gabapentin_doses,
|
||||
self.medicine_vars["propranolol"][0].get(),
|
||||
propranolol_doses,
|
||||
self.note_var.get(),
|
||||
]
|
||||
logger.debug(f"Adding entry: {entry}")
|
||||
@@ -241,7 +374,7 @@ class MedTrackerApp:
|
||||
if self.data_manager.delete_entry(date):
|
||||
edit_win.destroy()
|
||||
messagebox.showinfo(
|
||||
"Success", "Entry deleted successfully!", parent=edit_win
|
||||
"Success", "Entry deleted successfully!", parent=self.root
|
||||
)
|
||||
self.load_data()
|
||||
else:
|
||||
@@ -257,6 +390,13 @@ class MedTrackerApp:
|
||||
self.medicine_vars[key][0].set(0)
|
||||
self.note_var.set("")
|
||||
|
||||
# Clear dose entry fields
|
||||
for entry in self.dose_entries.values():
|
||||
entry.delete(0, tk.END)
|
||||
|
||||
# Update dose displays
|
||||
self._update_dose_displays()
|
||||
|
||||
def load_data(self) -> None:
|
||||
"""Load data from the CSV file into the table and graph."""
|
||||
logger.debug("Loading data from CSV.")
|
||||
@@ -270,9 +410,30 @@ class MedTrackerApp:
|
||||
|
||||
# Update the treeview with the data
|
||||
if not df.empty:
|
||||
for _index, row in df.iterrows():
|
||||
# Only show user-friendly columns in the table (not the dose columns)
|
||||
display_columns = [
|
||||
"date",
|
||||
"depression",
|
||||
"anxiety",
|
||||
"sleep",
|
||||
"appetite",
|
||||
"bupropion",
|
||||
"hydroxyzine",
|
||||
"gabapentin",
|
||||
"propranolol",
|
||||
"note",
|
||||
]
|
||||
|
||||
# Filter to only the columns we want to display
|
||||
if all(col in df.columns for col in display_columns):
|
||||
display_df = df[display_columns]
|
||||
else:
|
||||
# Fallback for old CSV format - just use all columns
|
||||
display_df = df
|
||||
|
||||
for _index, row in display_df.iterrows():
|
||||
self.tree.insert(parent="", index="end", values=list(row))
|
||||
logger.debug(f"Loaded {len(df)} entries into treeview.")
|
||||
logger.debug(f"Loaded {len(display_df)} entries into treeview.")
|
||||
|
||||
# Update the graph
|
||||
self.graph_manager.update_graph(df)
|
||||
|
||||
+182
-10
@@ -53,10 +53,49 @@ class UIManager:
|
||||
|
||||
def create_input_frame(self, parent_frame: ttk.Frame) -> dict[str, Any]:
|
||||
"""Create and configure the input frame with all widgets."""
|
||||
input_frame: ttk.LabelFrame = ttk.LabelFrame(parent_frame, text="New Entry")
|
||||
input_frame.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
|
||||
# Create main container for the scrollable input frame
|
||||
main_container = ttk.LabelFrame(parent_frame, text="New Entry")
|
||||
main_container.grid(row=1, column=0, padx=10, pady=10, sticky="nsew")
|
||||
main_container.grid_rowconfigure(0, weight=1)
|
||||
main_container.grid_columnconfigure(0, weight=1)
|
||||
|
||||
# Create canvas and scrollbar for scrolling
|
||||
canvas = tk.Canvas(main_container, highlightthickness=0)
|
||||
scrollbar = ttk.Scrollbar(
|
||||
main_container, orient="vertical", command=canvas.yview
|
||||
)
|
||||
canvas.configure(yscrollcommand=scrollbar.set)
|
||||
|
||||
# Create the actual input frame inside the canvas
|
||||
input_frame = ttk.Frame(canvas)
|
||||
input_frame.grid_columnconfigure(1, weight=1)
|
||||
|
||||
# Configure canvas scrolling
|
||||
def configure_scroll_region(event=None):
|
||||
canvas.configure(scrollregion=canvas.bbox("all"))
|
||||
|
||||
def on_mousewheel(event):
|
||||
canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
|
||||
|
||||
input_frame.bind("<Configure>", configure_scroll_region)
|
||||
canvas.bind("<MouseWheel>", on_mousewheel) # Windows/Linux
|
||||
canvas.bind("<Button-4>", lambda e: canvas.yview_scroll(-1, "units")) # Linux
|
||||
canvas.bind("<Button-5>", lambda e: canvas.yview_scroll(1, "units")) # Linux
|
||||
|
||||
# Place canvas and scrollbar in the container
|
||||
canvas.grid(row=0, column=0, sticky="nsew")
|
||||
scrollbar.grid(row=0, column=1, sticky="ns")
|
||||
|
||||
# Create window in canvas for the input frame
|
||||
canvas_window = canvas.create_window((0, 0), window=input_frame, anchor="nw")
|
||||
|
||||
# Configure canvas window width to fill available space
|
||||
def configure_canvas_width(event=None):
|
||||
canvas_width = canvas.winfo_width()
|
||||
canvas.itemconfig(canvas_window, width=canvas_width)
|
||||
|
||||
canvas.bind("<Configure>", configure_canvas_width)
|
||||
|
||||
# Create variables for symptoms
|
||||
symptom_vars: dict[str, tk.IntVar] = {
|
||||
"depression": tk.IntVar(value=0),
|
||||
@@ -85,13 +124,15 @@ class UIManager:
|
||||
variable=symptom_vars[var_name],
|
||||
).grid(row=idx, column=1, sticky="ew")
|
||||
|
||||
# Medicine checkboxes
|
||||
# Medicine tracking section with dose buttons
|
||||
ttk.Label(input_frame, text="Treatment:").grid(
|
||||
row=4, column=0, sticky="w", padx=5, pady=2
|
||||
)
|
||||
medicine_frame = ttk.LabelFrame(input_frame, text="Medicine")
|
||||
medicine_frame.grid(row=4, column=1, padx=0, pady=10, sticky="nsew")
|
||||
medicine_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
# Store medicine variables and dose tracking
|
||||
medicine_vars: dict[str, tuple[tk.IntVar, str]] = {
|
||||
"bupropion": (tk.IntVar(value=0), "Bupropion 150/300 mg"),
|
||||
"hydroxyzine": (tk.IntVar(value=0), "Hydroxyzine 25mg"),
|
||||
@@ -99,11 +140,44 @@ class UIManager:
|
||||
"propranolol": (tk.IntVar(value=0), "Propranolol 10mg"),
|
||||
}
|
||||
|
||||
for idx, (_name, (var, text)) in enumerate(medicine_vars.items()):
|
||||
ttk.Checkbutton(medicine_frame, text=text, variable=var).grid(
|
||||
row=idx, column=0, sticky="w", padx=5, pady=2
|
||||
# Store dose tracking elements for callback assignment later
|
||||
dose_buttons: dict[str, ttk.Button] = {}
|
||||
dose_entries: dict[str, ttk.Entry] = {}
|
||||
dose_displays: dict[str, tk.Text] = {}
|
||||
|
||||
for idx, (med_name, (var, text)) in enumerate(medicine_vars.items()):
|
||||
# Create a sub-frame for each medicine
|
||||
med_sub_frame = ttk.Frame(medicine_frame)
|
||||
med_sub_frame.grid(row=idx, column=0, sticky="ew", padx=5, pady=2)
|
||||
med_sub_frame.grid_columnconfigure(1, weight=1)
|
||||
|
||||
# Checkbox for medicine taken
|
||||
ttk.Checkbutton(med_sub_frame, text=text, variable=var).grid(
|
||||
row=0, column=0, sticky="w"
|
||||
)
|
||||
|
||||
# Dose tracking frame
|
||||
dose_frame = ttk.Frame(med_sub_frame)
|
||||
dose_frame.grid(row=0, column=1, sticky="ew", padx=(10, 0))
|
||||
dose_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
# Dose entry and button
|
||||
dose_var = tk.StringVar()
|
||||
dose_entry = ttk.Entry(dose_frame, textvariable=dose_var, width=10)
|
||||
dose_entry.grid(row=0, column=0, sticky="ew", padx=(0, 5))
|
||||
|
||||
dose_button = ttk.Button(dose_frame, text=f"Take {med_name.title()}")
|
||||
dose_button.grid(row=0, column=1)
|
||||
|
||||
# Display area for today's doses (read-only)
|
||||
dose_display = tk.Text(dose_frame, height=2, width=30, wrap=tk.WORD)
|
||||
dose_display.grid(row=1, column=0, columnspan=2, sticky="ew", pady=(2, 0))
|
||||
dose_display.config(state=tk.DISABLED)
|
||||
|
||||
dose_buttons[med_name] = dose_button
|
||||
dose_entries[med_name] = dose_entry
|
||||
dose_displays[med_name] = dose_display
|
||||
|
||||
# Note and Date fields
|
||||
note_var: tk.StringVar = tk.StringVar()
|
||||
date_var: tk.StringVar = tk.StringVar()
|
||||
@@ -127,9 +201,12 @@ class UIManager:
|
||||
|
||||
# Return all UI elements and variables
|
||||
return {
|
||||
"frame": input_frame,
|
||||
"frame": main_container,
|
||||
"symptom_vars": symptom_vars,
|
||||
"medicine_vars": medicine_vars,
|
||||
"dose_buttons": dose_buttons,
|
||||
"dose_entries": dose_entries,
|
||||
"dose_displays": dose_displays,
|
||||
"note_var": note_var,
|
||||
"date_var": date_var,
|
||||
}
|
||||
@@ -240,8 +317,50 @@ class UIManager:
|
||||
# Configure grid columns to expand properly
|
||||
edit_win.grid_columnconfigure(1, weight=1)
|
||||
|
||||
# Unpack values
|
||||
date, dep, anx, slp, app, bup, hydro, gaba, prop, note = values
|
||||
# Unpack values - handle both old and new CSV formats
|
||||
if len(values) == 10:
|
||||
# Old format: date, dep, anx, slp, app, bup, hydro, gaba, prop, note
|
||||
date, dep, anx, slp, app, bup, hydro, gaba, prop, note = values
|
||||
bup_doses, hydro_doses, gaba_doses, prop_doses = "", "", "", ""
|
||||
elif len(values) == 14:
|
||||
# New format with dose tracking
|
||||
(
|
||||
date,
|
||||
dep,
|
||||
anx,
|
||||
slp,
|
||||
app,
|
||||
bup,
|
||||
bup_doses,
|
||||
hydro,
|
||||
hydro_doses,
|
||||
gaba,
|
||||
gaba_doses,
|
||||
prop,
|
||||
prop_doses,
|
||||
note,
|
||||
) = values
|
||||
else:
|
||||
# Fallback for unexpected format
|
||||
self.logger.warning(f"Unexpected number of values in edit: {len(values)}")
|
||||
# Pad with default values
|
||||
values_list = list(values) + [""] * (14 - len(values))
|
||||
(
|
||||
date,
|
||||
dep,
|
||||
anx,
|
||||
slp,
|
||||
app,
|
||||
bup,
|
||||
bup_doses,
|
||||
hydro,
|
||||
hydro_doses,
|
||||
gaba,
|
||||
gaba_doses,
|
||||
prop,
|
||||
prop_doses,
|
||||
note,
|
||||
) = values_list[:14]
|
||||
|
||||
# Create variables and fields
|
||||
vars_dict = self._create_edit_fields(edit_win, date, dep, anx, slp, app)
|
||||
@@ -253,8 +372,21 @@ class UIManager:
|
||||
)
|
||||
vars_dict.update(med_vars)
|
||||
|
||||
# Note field
|
||||
# Dose information display (read-only)
|
||||
current_row += 1
|
||||
self._add_dose_display_to_edit(
|
||||
edit_win,
|
||||
current_row,
|
||||
{
|
||||
"bupropion": bup_doses,
|
||||
"hydroxyzine": hydro_doses,
|
||||
"gabapentin": gaba_doses,
|
||||
"propranolol": prop_doses,
|
||||
},
|
||||
)
|
||||
|
||||
# Note field
|
||||
current_row += 2 # Account for dose display
|
||||
vars_dict["note"] = tk.StringVar(value=str(note))
|
||||
ttk.Label(edit_win, text="Note:").grid(
|
||||
row=current_row, column=0, sticky="w", padx=5, pady=2
|
||||
@@ -441,3 +573,43 @@ class UIManager:
|
||||
text="Delete",
|
||||
command=lambda: callbacks["delete"](parent),
|
||||
).pack(side="left", padx=5)
|
||||
|
||||
def _add_dose_display_to_edit(
|
||||
self, parent: tk.Toplevel, row: int, dose_data: dict[str, str]
|
||||
) -> None:
|
||||
"""Add dose information display to edit window."""
|
||||
ttk.Label(parent, text="Recorded Doses:").grid(
|
||||
row=row, column=0, sticky="w", padx=5, pady=2
|
||||
)
|
||||
|
||||
dose_frame = ttk.LabelFrame(parent, text="Today's Doses (Read-Only)")
|
||||
dose_frame.grid(row=row, column=1, padx=5, pady=2, sticky="ew")
|
||||
|
||||
for idx, (medicine, doses_str) in enumerate(dose_data.items()):
|
||||
ttk.Label(dose_frame, text=f"{medicine.title()}:").grid(
|
||||
row=idx, column=0, sticky="w", padx=5, pady=1
|
||||
)
|
||||
|
||||
# Parse and display doses
|
||||
if doses_str:
|
||||
doses_display = []
|
||||
for dose_entry in doses_str.split("|"):
|
||||
if ":" in dose_entry:
|
||||
timestamp, dose = dose_entry.split(":", 1)
|
||||
# Format timestamp for display
|
||||
try:
|
||||
from datetime import datetime
|
||||
|
||||
dt = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
|
||||
time_str = dt.strftime("%H:%M")
|
||||
doses_display.append(f"{time_str}: {dose}")
|
||||
except ValueError:
|
||||
doses_display.append(dose_entry)
|
||||
|
||||
display_text = ", ".join(doses_display) if doses_display else "None"
|
||||
else:
|
||||
display_text = "None"
|
||||
|
||||
ttk.Label(dose_frame, text=display_text, wraplength=200).grid(
|
||||
row=idx, column=1, sticky="w", padx=5, pady=1
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user