Refactor method names for clarity and consistency across the application
Build and Push Docker Image / build-and-push (push) Has been cancelled
Build and Push Docker Image / build-and-push (push) Has been cancelled
- Renamed `initialize_csv` to `_initialize_csv_file` in `DataManager` for better clarity. - Updated method calls in `GraphManager` from `_create_toggle_controls` to `_create_chart_toggles` and `_on_toggle_changed` to `_handle_toggle_changed`. - Changed method names in `MedTrackerApp` from `on_closing` to `handle_window_closing`, `add_entry` to `add_new_entry`, and `load_data` to `refresh_data_display`. - Adjusted corresponding test method names in `TestMedTrackerApp` to reflect the new method names. - Updated `UIManager` method names from `setup_icon` to `setup_application_icon` and adjusted related tests accordingly.
This commit is contained in:
+24
-480
@@ -17,7 +17,7 @@ class UIManager:
|
||||
self.root: tk.Tk = root
|
||||
self.logger: logging.Logger = logger
|
||||
|
||||
def setup_icon(self, img_path: str) -> bool:
|
||||
def setup_application_icon(self, img_path: str) -> bool:
|
||||
"""Set up the application icon."""
|
||||
try:
|
||||
self.logger.info(f"Trying to load icon from: {img_path}")
|
||||
@@ -118,14 +118,10 @@ class UIManager:
|
||||
# Set focus to canvas to ensure it receives scroll events
|
||||
canvas.focus_set()
|
||||
|
||||
# Add mouse enter/leave events to manage focus for scrolling
|
||||
# Add mouse enter event to manage focus for scrolling
|
||||
def on_mouse_enter(event):
|
||||
canvas.focus_set()
|
||||
|
||||
def on_mouse_leave(event):
|
||||
# Don't change focus when leaving to avoid disrupting user interaction
|
||||
pass
|
||||
|
||||
main_container.bind("<Enter>", on_mouse_enter)
|
||||
canvas.bind("<Enter>", on_mouse_enter)
|
||||
|
||||
@@ -291,7 +287,7 @@ class UIManager:
|
||||
graph_frame.grid(row=0, column=0, columnspan=2, padx=10, pady=10, sticky="nsew")
|
||||
return graph_frame
|
||||
|
||||
def add_buttons(
|
||||
def add_action_buttons(
|
||||
self, frame: ttk.Frame, buttons_config: list[dict[str, Any]]
|
||||
) -> ttk.Frame:
|
||||
"""Add buttons to a frame based on configuration."""
|
||||
@@ -380,14 +376,10 @@ class UIManager:
|
||||
# Set focus to canvas to ensure it receives scroll events
|
||||
canvas.focus_set()
|
||||
|
||||
# Add mouse enter/leave events to manage focus for scrolling
|
||||
# Add mouse enter event to manage focus for scrolling
|
||||
def on_mouse_enter(event):
|
||||
canvas.focus_set()
|
||||
|
||||
def on_mouse_leave(event):
|
||||
# Don't change focus when leaving to avoid disrupting user interaction
|
||||
pass
|
||||
|
||||
edit_win.bind("<Enter>", on_mouse_enter)
|
||||
canvas.bind("<Enter>", on_mouse_enter)
|
||||
|
||||
@@ -467,7 +459,7 @@ class UIManager:
|
||||
) = values_list[:16]
|
||||
|
||||
# Create improved UI sections
|
||||
vars_dict = self._create_improved_edit_ui(
|
||||
vars_dict = self._create_edit_ui(
|
||||
main_container,
|
||||
date,
|
||||
dep,
|
||||
@@ -490,7 +482,7 @@ class UIManager:
|
||||
)
|
||||
|
||||
# Add action buttons
|
||||
self._add_improved_edit_buttons(main_container, vars_dict, callbacks, edit_win)
|
||||
self._add_edit_buttons(main_container, vars_dict, callbacks, edit_win)
|
||||
|
||||
# Update scroll region after adding all content
|
||||
edit_win.update_idletasks()
|
||||
@@ -505,7 +497,7 @@ class UIManager:
|
||||
|
||||
return edit_win
|
||||
|
||||
def _create_improved_edit_ui(
|
||||
def _create_edit_ui(
|
||||
self,
|
||||
parent: ttk.Frame,
|
||||
date: str,
|
||||
@@ -521,7 +513,7 @@ class UIManager:
|
||||
note: str,
|
||||
dose_data: dict[str, str],
|
||||
) -> dict[str, Any]:
|
||||
"""Create improved UI layout for edit window with better organization."""
|
||||
"""Create UI layout for edit window with organized sections."""
|
||||
vars_dict = {}
|
||||
row = 0
|
||||
|
||||
@@ -561,9 +553,7 @@ class UIManager:
|
||||
]
|
||||
|
||||
for i, (label, key, value) in enumerate(symptoms):
|
||||
self._create_improved_symptom_scale(
|
||||
symptoms_frame, i, label, key, value, vars_dict
|
||||
)
|
||||
self._create_symptom_scale(symptoms_frame, i, label, key, value, vars_dict)
|
||||
|
||||
row += 1
|
||||
|
||||
@@ -573,7 +563,7 @@ class UIManager:
|
||||
meds_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
# Create medicine checkboxes with better styling
|
||||
med_vars = self._create_improved_medicine_section(
|
||||
med_vars = self._create_medicine_section(
|
||||
meds_frame, bup, hydro, gaba, prop, quet
|
||||
)
|
||||
vars_dict.update(med_vars)
|
||||
@@ -585,7 +575,7 @@ class UIManager:
|
||||
dose_frame.grid(row=row, column=0, sticky="ew", pady=(0, 15))
|
||||
dose_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
dose_vars = self._create_improved_dose_tracking(dose_frame, dose_data)
|
||||
dose_vars = self._create_dose_tracking(dose_frame, dose_data)
|
||||
vars_dict.update(dose_vars)
|
||||
|
||||
row += 1
|
||||
@@ -612,7 +602,7 @@ class UIManager:
|
||||
|
||||
return vars_dict
|
||||
|
||||
def _create_improved_symptom_scale(
|
||||
def _create_symptom_scale(
|
||||
self,
|
||||
parent: ttk.Frame,
|
||||
row: int,
|
||||
@@ -621,7 +611,7 @@ class UIManager:
|
||||
value: int,
|
||||
vars_dict: dict[str, Any],
|
||||
) -> None:
|
||||
"""Create an improved symptom scale with better visual feedback."""
|
||||
"""Create a symptom scale with visual feedback."""
|
||||
# Ensure value is properly converted
|
||||
try:
|
||||
value = int(float(value)) if value not in ["", None] else 0
|
||||
@@ -698,10 +688,10 @@ class UIManager:
|
||||
scale.bind("<KeyRelease>", update_value_label)
|
||||
update_value_label() # Set initial color
|
||||
|
||||
def _create_improved_medicine_section(
|
||||
def _create_medicine_section(
|
||||
self, parent: ttk.Frame, bup: int, hydro: int, gaba: int, prop: int, quet: int
|
||||
) -> dict[str, tk.IntVar]:
|
||||
"""Create improved medicine checkboxes with better layout."""
|
||||
"""Create medicine checkboxes with organized layout."""
|
||||
vars_dict = {}
|
||||
|
||||
# Create a grid layout for medicines
|
||||
@@ -739,10 +729,10 @@ class UIManager:
|
||||
|
||||
return vars_dict
|
||||
|
||||
def _create_improved_dose_tracking(
|
||||
def _create_dose_tracking(
|
||||
self, parent: ttk.Frame, dose_data: dict[str, str]
|
||||
) -> dict[str, Any]:
|
||||
"""Create improved dose tracking interface."""
|
||||
"""Create dose tracking interface."""
|
||||
vars_dict = {}
|
||||
|
||||
# Create notebook for organized dose tracking
|
||||
@@ -797,7 +787,7 @@ class UIManager:
|
||||
# Take dose button
|
||||
def create_take_dose_command(med_name, entry_var, med_key):
|
||||
def take_dose():
|
||||
self._take_dose_improved(med_name, entry_var, med_key, vars_dict)
|
||||
self._take_dose(med_name, entry_var, med_key, vars_dict)
|
||||
|
||||
return take_dose
|
||||
|
||||
@@ -887,14 +877,14 @@ class UIManager:
|
||||
|
||||
# Always keep text widget enabled for user editing
|
||||
|
||||
def _take_dose_improved(
|
||||
def _take_dose(
|
||||
self,
|
||||
med_name: str,
|
||||
entry_var: tk.StringVar,
|
||||
med_key: str,
|
||||
vars_dict: dict[str, Any],
|
||||
) -> None:
|
||||
"""Handle taking a dose with improved feedback and state management."""
|
||||
"""Handle taking a dose with feedback and state management."""
|
||||
dose = entry_var.get().strip()
|
||||
|
||||
# Get the dose text widget - this is what the save function reads from
|
||||
@@ -956,20 +946,20 @@ class UIManager:
|
||||
parent=parent_window,
|
||||
)
|
||||
|
||||
def _add_improved_edit_buttons(
|
||||
def _add_edit_buttons(
|
||||
self,
|
||||
parent: ttk.Frame,
|
||||
vars_dict: dict[str, Any],
|
||||
callbacks: dict[str, Callable],
|
||||
edit_win: tk.Toplevel,
|
||||
) -> None:
|
||||
"""Add improved action buttons to edit window."""
|
||||
"""Add action buttons to edit window."""
|
||||
button_frame = ttk.Frame(parent)
|
||||
button_frame.grid(row=999, column=0, sticky="ew", pady=(20, 0))
|
||||
button_frame.grid_columnconfigure((0, 1, 2), weight=1)
|
||||
|
||||
# Save button
|
||||
def save_with_improved_data():
|
||||
def save_with_data():
|
||||
self.logger.debug("=== SAVE FUNCTION CALLED ===")
|
||||
|
||||
# Get note text from Text widget
|
||||
@@ -1028,7 +1018,7 @@ class UIManager:
|
||||
button_frame,
|
||||
text="💾 Save Changes",
|
||||
style="Accent.TButton",
|
||||
command=save_with_improved_data,
|
||||
command=save_with_data,
|
||||
)
|
||||
save_btn.grid(row=0, column=0, sticky="ew", padx=(0, 5))
|
||||
|
||||
@@ -1189,449 +1179,3 @@ class UIManager:
|
||||
except tk.TclError:
|
||||
# Handle potential errors when accessing children
|
||||
pass
|
||||
|
||||
def _create_edit_fields(
|
||||
self,
|
||||
parent: tk.Toplevel,
|
||||
date: str,
|
||||
dep: int,
|
||||
anx: int,
|
||||
slp: int,
|
||||
app: int,
|
||||
) -> dict[str, tk.StringVar | tk.IntVar]:
|
||||
"""Create fields for editing entry values."""
|
||||
vars_dict: dict[str, tk.StringVar | tk.IntVar] = {}
|
||||
|
||||
# Ensure values are converted to appropriate types
|
||||
try:
|
||||
app = int(app) if app != "" else 0
|
||||
except (ValueError, TypeError):
|
||||
self.logger.warning(f"Invalid appetite value: {app}, defaulting to 0")
|
||||
app = 0
|
||||
|
||||
value_map = {
|
||||
"date": date,
|
||||
"depression": dep,
|
||||
"anxiety": anx,
|
||||
"sleep": slp,
|
||||
"appetite": app,
|
||||
}
|
||||
|
||||
fields = [
|
||||
("Date", tk.StringVar, "date"),
|
||||
("Depression (0-10)", tk.IntVar, "depression"),
|
||||
("Anxiety (0-10)", tk.IntVar, "anxiety"),
|
||||
("Sleep (0-10)", tk.IntVar, "sleep"),
|
||||
("Appetite (0-10)", tk.IntVar, "appetite"),
|
||||
]
|
||||
|
||||
for idx, (label, var_type, key) in enumerate(fields):
|
||||
try:
|
||||
value = value_map[key]
|
||||
if var_type == tk.IntVar:
|
||||
try:
|
||||
value = int(float(value))
|
||||
except (ValueError, TypeError):
|
||||
value = 0
|
||||
self.logger.warning(
|
||||
f"Failed to convert {key} value: {value}, defaulting to 0"
|
||||
)
|
||||
else:
|
||||
value = str(value)
|
||||
except (ValueError, TypeError, KeyError):
|
||||
value = 0 if var_type == tk.IntVar else ""
|
||||
self.logger.warning(
|
||||
f"Missing or invalid value for {key}, defaulting to {value}"
|
||||
)
|
||||
|
||||
vars_dict[key] = var_type(value=value)
|
||||
ttk.Label(parent, text=f"{label}:").grid(
|
||||
row=idx + 1, column=0, sticky="w", padx=5, pady=2
|
||||
)
|
||||
|
||||
if var_type == tk.IntVar:
|
||||
self._create_scale_with_label(parent, idx + 1, vars_dict[key], value)
|
||||
else:
|
||||
ttk.Entry(parent, textvariable=vars_dict[key]).grid(
|
||||
row=idx + 1, column=1, sticky="ew"
|
||||
)
|
||||
|
||||
return vars_dict
|
||||
|
||||
def _create_scale_with_label(
|
||||
self, parent: tk.Toplevel, row: int, var: tk.IntVar, value: int
|
||||
) -> None:
|
||||
"""Create a scale with a value label."""
|
||||
scale_frame: ttk.Frame = ttk.Frame(parent)
|
||||
scale_frame.grid(row=row, column=1, sticky="ew", padx=5, pady=2)
|
||||
scale_frame.grid_columnconfigure(0, weight=1)
|
||||
|
||||
scale = ttk.Scale(
|
||||
scale_frame, from_=0, to=10, variable=var, orient=tk.HORIZONTAL
|
||||
)
|
||||
scale.grid(row=0, column=0, sticky="ew", padx=5)
|
||||
|
||||
# Add a value label to show the current value
|
||||
value_label = ttk.Label(scale_frame, width=3)
|
||||
value_label.grid(row=0, column=1, padx=(5, 0))
|
||||
|
||||
# Update label when scale value changes
|
||||
def update_label(event=None):
|
||||
value_label.configure(text=str(var.get()))
|
||||
|
||||
scale.bind("<Motion>", update_label)
|
||||
scale.bind("<ButtonRelease-1>", update_label)
|
||||
update_label() # Set initial value
|
||||
scale.set(value) # Explicitly set scale value
|
||||
|
||||
def _create_medicine_checkboxes(
|
||||
self,
|
||||
parent: tk.Toplevel,
|
||||
row: int,
|
||||
bup: int,
|
||||
hydro: int,
|
||||
gaba: int,
|
||||
prop: int,
|
||||
quet: int,
|
||||
) -> dict[str, tk.IntVar]:
|
||||
"""Create medicine checkboxes in the edit window."""
|
||||
ttk.Label(parent, text="Treatment:").grid(
|
||||
row=row, column=0, sticky="w", padx=5, pady=2
|
||||
)
|
||||
medicine_frame: ttk.LabelFrame = ttk.LabelFrame(parent, text="Medicine")
|
||||
medicine_frame.grid(row=row, column=1, padx=0, pady=10, sticky="nsew")
|
||||
|
||||
medicine_vars: dict[str, tuple[int, str]] = {
|
||||
"bupropion": (bup, "Bupropion 150/300 mg"),
|
||||
"hydroxyzine": (hydro, "Hydroxyzine 25mg"),
|
||||
"gabapentin": (gaba, "Gabapentin 100mg"),
|
||||
"propranolol": (prop, "Propranolol 10mg"),
|
||||
"quetiapine": (quet, "Quetiapine 25mg"),
|
||||
}
|
||||
|
||||
vars_dict: dict[str, tk.IntVar] = {}
|
||||
for idx, (key, (value, label)) in enumerate(medicine_vars.items()):
|
||||
vars_dict[key] = tk.IntVar(value=int(value))
|
||||
ttk.Checkbutton(medicine_frame, text=label, variable=vars_dict[key]).grid(
|
||||
row=idx, column=0, sticky="w", padx=5, pady=2
|
||||
)
|
||||
|
||||
return vars_dict
|
||||
|
||||
def _add_edit_window_buttons(
|
||||
self,
|
||||
parent: tk.Toplevel,
|
||||
row: int,
|
||||
vars_dict: dict[str, Any],
|
||||
callbacks: dict[str, Callable],
|
||||
) -> None:
|
||||
"""Add buttons to the edit window."""
|
||||
button_frame: ttk.Frame = ttk.Frame(parent)
|
||||
button_frame.grid(row=row, column=0, columnspan=2, pady=10)
|
||||
|
||||
# Save button - create a custom callback to handle dose data
|
||||
def save_with_doses():
|
||||
self.logger.debug("save_with_doses called")
|
||||
# Extract dose data from the text widgets
|
||||
dose_data = {}
|
||||
|
||||
for medicine in [
|
||||
"bupropion",
|
||||
"hydroxyzine",
|
||||
"gabapentin",
|
||||
"propranolol",
|
||||
"quetiapine",
|
||||
]:
|
||||
dose_text_key = f"{medicine}_doses_text"
|
||||
self.logger.debug(f"Looking for key: {dose_text_key}")
|
||||
|
||||
if dose_text_key in vars_dict and isinstance(
|
||||
vars_dict[dose_text_key], tk.Text
|
||||
):
|
||||
raw_text = vars_dict[dose_text_key].get(1.0, tk.END).strip()
|
||||
self.logger.debug(f"Raw text for {medicine}: '{raw_text}'")
|
||||
dose_data[medicine] = self._parse_dose_history_for_saving(
|
||||
raw_text, vars_dict["date"].get()
|
||||
)
|
||||
self.logger.debug(
|
||||
f"Parsed dose data for {medicine}: '{dose_data[medicine]}'"
|
||||
)
|
||||
else:
|
||||
self.logger.debug(
|
||||
f"Key {dose_text_key} not found in vars_dict or not a Text "
|
||||
"widget"
|
||||
)
|
||||
dose_data[medicine] = ""
|
||||
|
||||
callbacks["save"](
|
||||
parent,
|
||||
vars_dict["date"].get(),
|
||||
vars_dict["depression"].get(),
|
||||
vars_dict["anxiety"].get(),
|
||||
vars_dict["sleep"].get(),
|
||||
vars_dict["appetite"].get(),
|
||||
vars_dict["bupropion"].get(),
|
||||
vars_dict["hydroxyzine"].get(),
|
||||
vars_dict["gabapentin"].get(),
|
||||
vars_dict["propranolol"].get(),
|
||||
vars_dict["quetiapine"].get(),
|
||||
vars_dict["note"].get(),
|
||||
dose_data,
|
||||
)
|
||||
|
||||
ttk.Button(
|
||||
button_frame,
|
||||
text="Save",
|
||||
command=save_with_doses,
|
||||
).pack(side="left", padx=5)
|
||||
|
||||
# Cancel button
|
||||
ttk.Button(button_frame, text="Cancel", command=parent.destroy).pack(
|
||||
side="left", padx=5
|
||||
)
|
||||
|
||||
# Delete button
|
||||
ttk.Button(
|
||||
button_frame,
|
||||
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]
|
||||
) -> dict[str, tk.Text]:
|
||||
"""Add comprehensive dose tracking to edit window with punch buttons."""
|
||||
ttk.Label(parent, text="Dose Tracking:").grid(
|
||||
row=row, column=0, sticky="w", padx=5, pady=2
|
||||
)
|
||||
|
||||
dose_frame = ttk.LabelFrame(parent, text="Medicine Doses")
|
||||
dose_frame.grid(row=row, column=1, padx=5, pady=2, sticky="ew")
|
||||
dose_frame.grid_columnconfigure(2, weight=1)
|
||||
|
||||
dose_vars = {}
|
||||
|
||||
for idx, (medicine, doses_str) in enumerate(dose_data.items()):
|
||||
# Medicine label
|
||||
med_label = ttk.Label(dose_frame, text=f"{medicine.title()}:")
|
||||
med_label.grid(row=idx, column=0, sticky="w", padx=5, pady=2)
|
||||
|
||||
# Dose entry field for new doses
|
||||
dose_entry_var = tk.StringVar()
|
||||
dose_entry = ttk.Entry(dose_frame, textvariable=dose_entry_var, width=12)
|
||||
dose_entry.grid(row=idx, column=1, sticky="w", padx=5, pady=2)
|
||||
|
||||
# Store entry variable in dose_vars for access from punch button
|
||||
dose_vars[f"{medicine}_entry_var"] = dose_entry_var
|
||||
|
||||
# Display area for existing doses (editable)
|
||||
dose_text = tk.Text(dose_frame, height=3, width=40, wrap=tk.WORD)
|
||||
dose_text.grid(row=idx, column=2, sticky="ew", padx=5, pady=2)
|
||||
|
||||
# Store text widget in dose_vars
|
||||
dose_vars[f"{medicine}_doses_text"] = dose_text
|
||||
|
||||
# Punch button to record dose immediately
|
||||
def create_punch_command(med_name, entry_var, text_widget):
|
||||
"""Create a punch command that captures the specific widgets."""
|
||||
|
||||
def punch_command():
|
||||
self._punch_dose_direct(med_name, entry_var, text_widget)
|
||||
|
||||
return punch_command
|
||||
|
||||
punch_button = ttk.Button(
|
||||
dose_frame,
|
||||
text=f"Take {medicine.title()}",
|
||||
width=15,
|
||||
command=create_punch_command(medicine, dose_entry_var, dose_text),
|
||||
)
|
||||
punch_button.grid(row=idx, column=3, sticky="w", padx=5, pady=2)
|
||||
|
||||
# Parse and format doses for editing
|
||||
if doses_str and str(doses_str) != "nan":
|
||||
doses_str = str(doses_str) # Convert to string in case it's a float/NaN
|
||||
formatted_doses = []
|
||||
for dose_entry_str in doses_str.split("|"):
|
||||
if ":" in dose_entry_str:
|
||||
timestamp, dose = dose_entry_str.split(":", 1)
|
||||
# Format timestamp for display
|
||||
try:
|
||||
dt = datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")
|
||||
time_str = dt.strftime("%H:%M")
|
||||
formatted_doses.append(f"{time_str}: {dose}")
|
||||
except ValueError:
|
||||
formatted_doses.append(dose_entry_str)
|
||||
|
||||
if formatted_doses:
|
||||
dose_text.insert(1.0, "\n".join(formatted_doses))
|
||||
else:
|
||||
dose_text.insert(1.0, "No doses recorded")
|
||||
else:
|
||||
dose_text.insert(1.0, "No doses recorded")
|
||||
|
||||
# Add help text below the dose display
|
||||
help_label = ttk.Label(
|
||||
dose_frame,
|
||||
text="Format: HH:MM: dose",
|
||||
font=("TkDefaultFont", 8),
|
||||
foreground="gray",
|
||||
)
|
||||
help_label.grid(row=idx, column=4, sticky="w", padx=5, pady=2)
|
||||
|
||||
return dose_vars
|
||||
|
||||
def _punch_dose_direct(
|
||||
self,
|
||||
medicine_name: str,
|
||||
dose_entry_var: tk.StringVar,
|
||||
dose_text_widget: tk.Text,
|
||||
) -> None:
|
||||
"""Handle punch dose button with direct widget references."""
|
||||
dose = dose_entry_var.get().strip()
|
||||
|
||||
# Find the parent edit window
|
||||
parent_window = dose_text_widget.winfo_toplevel()
|
||||
|
||||
if not dose:
|
||||
messagebox.showerror(
|
||||
"Error",
|
||||
f"Please enter a dose amount for {medicine_name}",
|
||||
parent=parent_window,
|
||||
)
|
||||
return
|
||||
|
||||
# Get current time
|
||||
now = datetime.now()
|
||||
time_str = now.strftime("%H:%M")
|
||||
|
||||
# Get current content
|
||||
current_content = dose_text_widget.get(1.0, tk.END).strip()
|
||||
|
||||
# Add new dose entry
|
||||
new_dose_line = f"{time_str}: {dose}"
|
||||
|
||||
if current_content == "No doses recorded" or not current_content:
|
||||
dose_text_widget.delete(1.0, tk.END)
|
||||
dose_text_widget.insert(1.0, new_dose_line)
|
||||
else:
|
||||
dose_text_widget.insert(tk.END, f"\n{new_dose_line}")
|
||||
|
||||
# Clear the entry field
|
||||
dose_entry_var.set("")
|
||||
|
||||
# Show success message
|
||||
messagebox.showinfo(
|
||||
"Success",
|
||||
f"{medicine_name.title()} dose recorded: {dose} at {time_str}",
|
||||
parent=parent_window,
|
||||
)
|
||||
|
||||
def _punch_dose_in_edit(self, medicine_name: str, dose_vars: dict) -> None:
|
||||
"""Handle punch dose button in edit window."""
|
||||
dose_entry_var = dose_vars.get(f"{medicine_name}_entry_var")
|
||||
dose_text_widget = dose_vars.get(f"{medicine_name}_doses_text")
|
||||
|
||||
if not dose_entry_var or not dose_text_widget:
|
||||
return
|
||||
|
||||
dose = dose_entry_var.get().strip()
|
||||
|
||||
# Find the parent edit window
|
||||
parent_window = dose_text_widget.winfo_toplevel()
|
||||
|
||||
if not dose:
|
||||
messagebox.showerror(
|
||||
"Error",
|
||||
f"Please enter a dose amount for {medicine_name}",
|
||||
parent=parent_window,
|
||||
)
|
||||
return
|
||||
|
||||
# Get current time
|
||||
now = datetime.now()
|
||||
time_str = now.strftime("%H:%M")
|
||||
|
||||
# Get current content
|
||||
current_content = dose_text_widget.get(1.0, tk.END).strip()
|
||||
|
||||
# Add new dose entry
|
||||
new_dose_line = f"{time_str}: {dose}"
|
||||
|
||||
if current_content == "No doses recorded" or not current_content:
|
||||
dose_text_widget.delete(1.0, tk.END)
|
||||
dose_text_widget.insert(1.0, new_dose_line)
|
||||
else:
|
||||
dose_text_widget.insert(tk.END, f"\n{new_dose_line}")
|
||||
|
||||
# Clear the entry field
|
||||
dose_entry_var.set("")
|
||||
|
||||
# Show success message
|
||||
messagebox.showinfo(
|
||||
"Success",
|
||||
f"{medicine_name.title()} dose recorded: {dose} at {time_str}",
|
||||
parent=parent_window,
|
||||
)
|
||||
|
||||
def _parse_dose_text(self, text: str, date: str) -> str:
|
||||
"""Parse dose text from edit window back to CSV format."""
|
||||
self.logger.debug(
|
||||
f"_parse_dose_text called with text: '{text}' and date: '{date}'"
|
||||
)
|
||||
|
||||
if not text or text == "No doses recorded":
|
||||
self.logger.debug(
|
||||
"Text is empty or 'No doses recorded', returning empty string"
|
||||
)
|
||||
return ""
|
||||
|
||||
lines = text.strip().split("\n")
|
||||
dose_entries = []
|
||||
|
||||
for line in lines:
|
||||
line = line.strip()
|
||||
if ":" in line and line != "No doses recorded":
|
||||
try:
|
||||
# Try to parse HH:MM: dose format
|
||||
# Split on ': ' (colon followed by space) to separate time from dose
|
||||
if ": " in line:
|
||||
time_part, dose_part = line.split(": ", 1)
|
||||
else:
|
||||
# Fallback: split on first colon after HH:MM pattern
|
||||
colon_indices = [
|
||||
i for i, char in enumerate(line) if char == ":"
|
||||
]
|
||||
if len(colon_indices) >= 2:
|
||||
# Take everything up to the second colon as time
|
||||
second_colon_idx = colon_indices[1]
|
||||
time_part = line[:second_colon_idx]
|
||||
dose_part = line[second_colon_idx + 1 :].strip()
|
||||
else:
|
||||
continue
|
||||
|
||||
dose_part = dose_part.strip()
|
||||
|
||||
# Create timestamp for today
|
||||
from datetime import datetime
|
||||
|
||||
time_str = time_part.strip()
|
||||
# Parse just the time (HH:MM format)
|
||||
time_obj = datetime.strptime(time_str, "%H:%M")
|
||||
|
||||
# Create full timestamp with today's date
|
||||
today = datetime.strptime(date, "%m/%d/%Y")
|
||||
full_timestamp = today.replace(
|
||||
hour=time_obj.hour, minute=time_obj.minute, second=0
|
||||
)
|
||||
|
||||
timestamp_str = full_timestamp.strftime("%Y-%m-%d %H:%M:%S")
|
||||
dose_entries.append(f"{timestamp_str}:{dose_part}")
|
||||
except ValueError:
|
||||
# If parsing fails, skip this line
|
||||
self.logger.debug(f"Failed to parse line: '{line}'")
|
||||
continue
|
||||
|
||||
result = "|".join(dose_entries)
|
||||
self.logger.debug(f"_parse_dose_text returning: '{result}'")
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user