refactor: Improve dose entry handling in UIManager for better synchronization and user experience

This commit is contained in:
William Valentin
2025-08-10 09:39:18 -07:00
parent 2396781d66
commit 1fa9f9cd01
+66 -64
View File
@@ -1,3 +1,4 @@
import contextlib
import logging import logging
import os import os
import sys import sys
@@ -1446,60 +1447,10 @@ class UIManager:
quick_frame = ttk.Frame(entry_frame) quick_frame = ttk.Frame(entry_frame)
quick_frame.grid(row=0, column=1, padx=10, pady=5, sticky="w") quick_frame.grid(row=0, column=1, padx=10, pady=5, sticky="w")
# Create the dose StringVar that will be used for saving # Create the dose StringVar; we'll keep it in sync with the text widget
dose_string_var = tk.StringVar(value=str(dose_str)) dose_string_var = tk.StringVar(value="")
vars_dict[f"{medicine_key}_doses"] = dose_string_var vars_dict[f"{medicine_key}_doses"] = dose_string_var
# Punch button - updated to use the StringVar properly
def create_punch_callback(med_key, entry_var, dose_var):
def punch_dose():
dose = entry_var.get().strip()
if dose:
from datetime import datetime
# Format timestamp for display (12-hour format with AM/PM)
timestamp = datetime.now().strftime("%I:%M %p")
new_dose = f"{timestamp} - {dose}"
current_doses = dose_var.get()
if current_doses and current_doses.strip():
# Check if current content is placeholder text
if "No doses recorded" in current_doses:
dose_var.set(new_dose)
else:
dose_var.set(current_doses + f"\n{new_dose}")
else:
dose_var.set(new_dose)
entry_var.set("")
return punch_dose
punch_btn = ttk.Button(
quick_frame,
text=f"Take {medicine.display_name}",
command=create_punch_callback(
medicine_key, dose_entry_var, dose_string_var
),
width=15,
)
punch_btn.grid(row=0, column=0, padx=5)
# Quick dose buttons
quick_doses = self.medicine_manager.get_quick_doses(medicine_key)
for i, dose in enumerate(quick_doses[:3]): # Limit to 3 quick doses
def create_quick_callback(d, entry_var=dose_entry_var):
return lambda: entry_var.set(d)
btn = ttk.Button(
quick_frame,
text=f"{dose}mg",
command=create_quick_callback(dose),
width=8,
)
btn.grid(row=0, column=i + 1, padx=2)
# Dose history section # Dose history section
history_frame = ttk.LabelFrame( history_frame = ttk.LabelFrame(
tab_frame, text="Dose History (HH:MM: dose)", padding="10" tab_frame, text="Dose History (HH:MM: dose)", padding="10"
@@ -1521,6 +1472,12 @@ class UIManager:
# Populate with existing doses using the proper formatting method # Populate with existing doses using the proper formatting method
self._populate_dose_history(dose_text, dose_str) self._populate_dose_history(dose_text, dose_str)
# Initialize the StringVar from the displayed content for consistency
try:
current_display = dose_text.get("1.0", tk.END).strip()
dose_string_var.set(current_display)
except Exception:
dose_string_var.set("")
# Bind text widget to update string var - fixed closure issue # Bind text widget to update string var - fixed closure issue
def create_update_callback(text_widget, dose_var): def create_update_callback(text_widget, dose_var):
@@ -1534,21 +1491,66 @@ class UIManager:
dose_text.bind("<KeyRelease>", update_callback) dose_text.bind("<KeyRelease>", update_callback)
dose_text.bind("<FocusOut>", update_callback) dose_text.bind("<FocusOut>", update_callback)
# Also update text widget when StringVar changes (for punch button) # Do not mirror StringVar back to Text automatically to avoid overwriting
def create_var_to_text_callback(text_widget, string_var): # user edits or formatted history; we keep var in sync from Text only.
def update_text_from_var(*args):
current_text = text_widget.get("1.0", tk.END).strip()
var_content = string_var.get()
if current_text != var_content:
text_widget.delete("1.0", tk.END)
text_widget.insert("1.0", var_content)
return update_text_from_var # Punch button - append to the Text widget then sync the StringVar
def create_punch_callback(med_key, entry_var, text_widget, dose_var):
def punch_dose():
dose = entry_var.get().strip()
if not dose:
return
from datetime import datetime
var_to_text_callback = create_var_to_text_callback( # Format timestamp for display (12-hour format with AM/PM)
dose_text, dose_string_var timestamp = datetime.now().strftime("%I:%M %p")
new_dose_line = f"{timestamp} - {dose}"
# Ensure widget is editable and read current content
with contextlib.suppress(Exception):
text_widget.configure(state="normal")
current = text_widget.get("1.0", tk.END).strip()
# Replace placeholder or append
if not current or current == "No doses recorded today":
updated = new_dose_line
else:
updated = current + "\n" + new_dose_line
# Write back to the widget and sync the StringVar
text_widget.delete("1.0", tk.END)
text_widget.insert("1.0", updated)
dose_var.set(updated)
# Clear the quick entry
entry_var.set("")
return punch_dose
punch_btn = ttk.Button(
quick_frame,
text=f"Take {medicine.display_name}",
command=create_punch_callback(
medicine_key, dose_entry_var, dose_text, dose_string_var
),
width=15,
) )
dose_string_var.trace("w", var_to_text_callback) punch_btn.grid(row=0, column=0, padx=5)
# Quick dose buttons
quick_doses = self.medicine_manager.get_quick_doses(medicine_key)
for i, dose in enumerate(quick_doses[:3]): # Limit to 3 quick doses
def create_quick_callback(d, entry_var=dose_entry_var):
return lambda: entry_var.set(d)
btn = ttk.Button(
quick_frame,
text=f"{dose}mg",
command=create_quick_callback(dose),
width=8,
)
btn.grid(row=0, column=i + 1, padx=2)
# Scrollbar for dose text # Scrollbar for dose text
dose_scroll = ttk.Scrollbar( dose_scroll = ttk.Scrollbar(