Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1d310dd081 | |||
| abd1fa33cf | |||
| 03ef9e761a | |||
| ca1f8c976d | |||
| 7392709a27 | |||
| 623050478a |
+1
-1
@@ -47,7 +47,7 @@ htmlcov/
|
|||||||
.pylint.d/
|
.pylint.d/
|
||||||
|
|
||||||
# IDEs and editors
|
# IDEs and editors
|
||||||
#.vscode/
|
.vscode/
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
.idea/
|
.idea/
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
TARGET=thechart
|
TARGET=thechart
|
||||||
VERSION=1.6.1
|
VERSION=1.7.5
|
||||||
ROOT=/home/will
|
ROOT=/home/will
|
||||||
ICON=chart-671.png
|
ICON=chart-671.png
|
||||||
SHELL=fish
|
SHELL=fish
|
||||||
@@ -85,7 +85,7 @@ install: ## Set up the development environment
|
|||||||
@echo "To run tests: make test"
|
@echo "To run tests: make test"
|
||||||
build: ## Build the Docker image
|
build: ## Build the Docker image
|
||||||
@echo "Building the Docker image..."
|
@echo "Building the Docker image..."
|
||||||
docker buildx build --platform linux/amd64,linux/arm64 -t ${IMAGE} --push .
|
docker buildx build --platform linux/amd64 -t ${IMAGE} --push .
|
||||||
deploy: ## Deploy the application as a standalone executable
|
deploy: ## Deploy the application as a standalone executable
|
||||||
@echo "Deploying the application..."
|
@echo "Deploying the application..."
|
||||||
pyinstaller --name ${TARGET} --optimize 2 --onefile --windowed --hidden-import='PIL._tkinter_finder' --icon='${ICON}' --add-data="./.env:." --add-data='./chart-671.png:.' --add-data='./thechart_data.csv:.' --log-level=DEBUG src/main.py
|
pyinstaller --name ${TARGET} --optimize 2 --onefile --windowed --hidden-import='PIL._tkinter_finder' --icon='${ICON}' --add-data="./.env:." --add-data='./chart-671.png:.' --add-data='./thechart_data.csv:.' --log-level=DEBUG src/main.py
|
||||||
@@ -121,21 +121,6 @@ test-watch: ## Run tests in watch mode
|
|||||||
test-debug: ## Run tests with debug output
|
test-debug: ## Run tests with debug output
|
||||||
@echo "Running tests with debug output..."
|
@echo "Running tests with debug output..."
|
||||||
.venv/bin/python -m pytest tests/ -v -s --tb=long --cov=src
|
.venv/bin/python -m pytest tests/ -v -s --tb=long --cov=src
|
||||||
test-dose-tracking: ## Test the dose tracking functionality
|
|
||||||
@echo "Testing dose tracking functionality..."
|
|
||||||
.venv/bin/python scripts/test_dose_tracking.py
|
|
||||||
test-scrollable-input: ## Test the scrollable input frame UI
|
|
||||||
@echo "Testing scrollable input frame..."
|
|
||||||
.venv/bin/python scripts/test_scrollable_input.py
|
|
||||||
test-edit-functionality: ## Test the enhanced edit functionality
|
|
||||||
@echo "Testing edit functionality..."
|
|
||||||
.venv/bin/python scripts/test_edit_functionality.py
|
|
||||||
test-edit-window: $(VENV_ACTIVATE) ## Test edit window functionality (save and delete)
|
|
||||||
@echo "Running edit window functionality test..."
|
|
||||||
$(PYTHON) scripts/test_edit_window_functionality.py
|
|
||||||
test-dose-editing: $(VENV_ACTIVATE) ## Test dose editing functionality in edit window
|
|
||||||
@echo "Running dose editing functionality test..."
|
|
||||||
$(PYTHON) scripts/test_dose_editing_functionality.py
|
|
||||||
lint: ## Run the linter
|
lint: ## Run the linter
|
||||||
@echo "Running the linter..."
|
@echo "Running the linter..."
|
||||||
docker-compose exec ${TARGET} pipenv run pre-commit run --all-files
|
docker-compose exec ${TARGET} pipenv run pre-commit run --all-files
|
||||||
@@ -157,4 +142,4 @@ commit-emergency: ## Emergency commit (bypasses pre-commit hooks) - USE SPARINGL
|
|||||||
@read -p "Enter commit message: " msg; \
|
@read -p "Enter commit message: " msg; \
|
||||||
git add . && git commit --no-verify -m "$$msg"
|
git add . && git commit --no-verify -m "$$msg"
|
||||||
@echo "✅ Emergency commit completed. Please run tests manually when possible."
|
@echo "✅ Emergency commit completed. Please run tests manually when possible."
|
||||||
.PHONY: install clean reinstall check-env build attach deploy run start stop test lint format shell requirements commit-emergency test-dose-tracking test-scrollable-input test-edit-functionality test-edit-window test-dose-editing migrate-csv help
|
.PHONY: install clean reinstall check-env build attach deploy run start stop test lint format shell requirements commit-emergency help
|
||||||
|
|||||||
+3
-3
@@ -1,19 +1,19 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
CONTAINER_ENGINE="docker" # podman | docker
|
CONTAINER_ENGINE="docker" # podman | docker
|
||||||
VERSION="v1.0.0"
|
VERSION="v1.7.5"
|
||||||
REGISTRY="gitea-http.taildb3494.ts.net/will/thechart"
|
REGISTRY="gitea-http.taildb3494.ts.net/will/thechart"
|
||||||
|
|
||||||
if [ "$CONTAINER_ENGINE" == "podman" ];
|
if [ "$CONTAINER_ENGINE" == "podman" ];
|
||||||
then
|
then
|
||||||
buildah build \
|
buildah build \
|
||||||
-t $REGISTRY:$VERSION \
|
-t $REGISTRY:$VERSION \
|
||||||
--platform linux/amd64,linux/arm64/v8 \
|
--platform linux/amd64 \
|
||||||
--no-cache .
|
--no-cache .
|
||||||
else
|
else
|
||||||
DOCKER_BUILDKIT=1 \
|
DOCKER_BUILDKIT=1 \
|
||||||
docker buildx build \
|
docker buildx build \
|
||||||
--platform linux/amd64,linux/arm64/v8 \
|
--platform linux/amd64 \
|
||||||
-t $REGISTRY:$VERSION \
|
-t $REGISTRY:$VERSION \
|
||||||
--no-cache \
|
--no-cache \
|
||||||
--push .
|
--push .
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "thechart"
|
name = "thechart"
|
||||||
version = "1.6.1"
|
version = "1.7.5"
|
||||||
description = "Chart to monitor your medication intake over time."
|
description = "Chart to monitor your medication intake over time."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test script to verify note field saving functionality
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
# Add src directory to path to import modules
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
||||||
|
|
||||||
|
from data_manager import DataManager
|
||||||
|
from medicine_manager import MedicineManager
|
||||||
|
from pathology_manager import PathologyManager
|
||||||
|
|
||||||
|
|
||||||
|
def test_note_saving():
|
||||||
|
"""Test note saving functionality by checking current data"""
|
||||||
|
print("Testing note saving functionality...")
|
||||||
|
|
||||||
|
# Initialize logger
|
||||||
|
logger = logging.getLogger("test")
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
|
||||||
|
# Initialize managers
|
||||||
|
medicine_manager = MedicineManager("medicines.json")
|
||||||
|
pathology_manager = PathologyManager("pathologies.json")
|
||||||
|
data_manager = DataManager(
|
||||||
|
"thechart_data.csv", logger, medicine_manager, pathology_manager
|
||||||
|
)
|
||||||
|
|
||||||
|
# Load current data
|
||||||
|
df = data_manager.load_data()
|
||||||
|
|
||||||
|
if df.empty:
|
||||||
|
print("No data found in CSV file")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"Found {len(df)} entries in the data file")
|
||||||
|
|
||||||
|
# Check if we have any entries with notes
|
||||||
|
entries_with_notes = df[df["note"].notna() & (df["note"] != "")].copy()
|
||||||
|
|
||||||
|
print(f"Entries with notes: {len(entries_with_notes)}")
|
||||||
|
|
||||||
|
if len(entries_with_notes) > 0:
|
||||||
|
print("\nEntries with notes:")
|
||||||
|
for _, row in entries_with_notes.iterrows():
|
||||||
|
note_preview = (
|
||||||
|
row["note"][:50] + "..." if len(str(row["note"])) > 50 else row["note"]
|
||||||
|
)
|
||||||
|
print(f" Date: {row['date']}, Note: {note_preview}")
|
||||||
|
|
||||||
|
# Show the most recent entry
|
||||||
|
if len(df) > 0:
|
||||||
|
latest_entry = df.iloc[-1]
|
||||||
|
print("\nMost recent entry:")
|
||||||
|
print(f" Date: {latest_entry['date']}")
|
||||||
|
print(f" Note: '{latest_entry['note']}'")
|
||||||
|
print(f" Note length: {len(str(latest_entry['note']))}")
|
||||||
|
is_empty = pd.isna(latest_entry["note"]) or latest_entry["note"] == ""
|
||||||
|
print(f" Note is empty/null: {is_empty}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_note_saving()
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test the update_entry functionality with notes
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Add src directory to path to import modules
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
|
||||||
|
|
||||||
|
from data_manager import DataManager
|
||||||
|
from medicine_manager import MedicineManager
|
||||||
|
from pathology_manager import PathologyManager
|
||||||
|
|
||||||
|
|
||||||
|
def test_update_entry_with_note():
|
||||||
|
"""Test updating an entry with a note"""
|
||||||
|
print("Testing update_entry functionality with notes...")
|
||||||
|
|
||||||
|
# Initialize logger
|
||||||
|
logger = logging.getLogger("test")
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
# Add console handler to see debug output
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
handler.setLevel(logging.DEBUG)
|
||||||
|
formatter = logging.Formatter("%(levelname)s - %(message)s")
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
# Initialize managers
|
||||||
|
medicine_manager = MedicineManager("medicines.json")
|
||||||
|
pathology_manager = PathologyManager("pathologies.json")
|
||||||
|
data_manager = DataManager(
|
||||||
|
"thechart_data.csv", logger, medicine_manager, pathology_manager
|
||||||
|
)
|
||||||
|
|
||||||
|
# Load current data
|
||||||
|
df = data_manager.load_data()
|
||||||
|
|
||||||
|
if df.empty:
|
||||||
|
print("No data found in CSV file")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"Found {len(df)} entries in the data file")
|
||||||
|
|
||||||
|
# Find the most recent entry to test with
|
||||||
|
latest_entry = df.iloc[-1].copy()
|
||||||
|
original_date = latest_entry["date"]
|
||||||
|
|
||||||
|
print(f"Testing with entry: {original_date}")
|
||||||
|
print(f"Current note: '{latest_entry['note']}'")
|
||||||
|
|
||||||
|
# Create test values - keep everything the same but change the note
|
||||||
|
test_note = "This is a test note to verify saving functionality!"
|
||||||
|
|
||||||
|
# Build values list (same format as the UI would send)
|
||||||
|
values = [original_date] # date
|
||||||
|
|
||||||
|
# Add pathology values
|
||||||
|
pathology_keys = pathology_manager.get_pathology_keys()
|
||||||
|
for key in pathology_keys:
|
||||||
|
values.append(latest_entry.get(key, 0))
|
||||||
|
|
||||||
|
# Add medicine values and doses
|
||||||
|
medicine_keys = medicine_manager.get_medicine_keys()
|
||||||
|
for key in medicine_keys:
|
||||||
|
values.append(latest_entry.get(key, 0)) # medicine checkbox
|
||||||
|
values.append(latest_entry.get(f"{key}_doses", "")) # medicine doses
|
||||||
|
|
||||||
|
# Add the test note
|
||||||
|
values.append(test_note)
|
||||||
|
|
||||||
|
print(f"Values to save: {values}")
|
||||||
|
print(f"Note in values: '{values[-1]}'")
|
||||||
|
|
||||||
|
# Test the update
|
||||||
|
success = data_manager.update_entry(original_date, values)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
print("Update successful!")
|
||||||
|
|
||||||
|
# Reload and verify
|
||||||
|
df_after = data_manager.load_data()
|
||||||
|
updated_entry = df_after[df_after["date"] == original_date].iloc[0]
|
||||||
|
|
||||||
|
print(f"Note after update: '{updated_entry['note']}'")
|
||||||
|
print(f"Note correctly saved: {updated_entry['note'] == test_note}")
|
||||||
|
|
||||||
|
# Reset the note back to original
|
||||||
|
values[-1] = latest_entry["note"]
|
||||||
|
data_manager.update_entry(original_date, values)
|
||||||
|
print("Reverted note back to original")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("Update failed!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_update_entry_with_note()
|
||||||
+32
-344
@@ -417,8 +417,8 @@ class UIManager:
|
|||||||
# Extract note (should be the last value)
|
# Extract note (should be the last value)
|
||||||
note = values_list[-1] if len(values_list) > 0 else ""
|
note = values_list[-1] if len(values_list) > 0 else ""
|
||||||
|
|
||||||
# Create improved UI sections dynamically
|
# Create improved UI sections
|
||||||
vars_dict = self._create_edit_ui_dynamic(
|
vars_dict = self._create_edit_ui(
|
||||||
main_container,
|
main_container,
|
||||||
date,
|
date,
|
||||||
pathology_values,
|
pathology_values,
|
||||||
@@ -443,7 +443,7 @@ class UIManager:
|
|||||||
|
|
||||||
return edit_win
|
return edit_win
|
||||||
|
|
||||||
def _create_edit_ui_dynamic(
|
def _create_edit_ui(
|
||||||
self,
|
self,
|
||||||
parent: ttk.Frame,
|
parent: ttk.Frame,
|
||||||
date: str,
|
date: str,
|
||||||
@@ -500,7 +500,7 @@ class UIManager:
|
|||||||
meds_frame.grid_columnconfigure(0, weight=1)
|
meds_frame.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
# Create medicine checkboxes dynamically
|
# Create medicine checkboxes dynamically
|
||||||
med_vars = self._create_medicine_section_dynamic(meds_frame, medicine_values)
|
med_vars = self._create_medicine_section(meds_frame, medicine_values)
|
||||||
vars_dict.update(med_vars)
|
vars_dict.update(med_vars)
|
||||||
|
|
||||||
row += 1
|
row += 1
|
||||||
@@ -510,7 +510,7 @@ class UIManager:
|
|||||||
dose_frame.grid(row=row, column=0, sticky="ew", pady=(0, 15))
|
dose_frame.grid(row=row, column=0, sticky="ew", pady=(0, 15))
|
||||||
dose_frame.grid_columnconfigure(0, weight=1)
|
dose_frame.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
dose_vars = self._create_dose_tracking_dynamic(dose_frame, medicine_doses)
|
dose_vars = self._create_dose_tracking(dose_frame, medicine_doses)
|
||||||
vars_dict.update(dose_vars)
|
vars_dict.update(dose_vars)
|
||||||
|
|
||||||
row += 1
|
row += 1
|
||||||
@@ -532,6 +532,7 @@ class UIManager:
|
|||||||
)
|
)
|
||||||
note_text.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
|
note_text.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
|
||||||
note_text.insert("1.0", str(note))
|
note_text.insert("1.0", str(note))
|
||||||
|
vars_dict["note_text"] = note_text # Store the widget for access during save
|
||||||
|
|
||||||
# Bind text widget to string var for easy access
|
# Bind text widget to string var for easy access
|
||||||
def update_note(*args):
|
def update_note(*args):
|
||||||
@@ -542,111 +543,6 @@ class UIManager:
|
|||||||
|
|
||||||
return vars_dict
|
return vars_dict
|
||||||
|
|
||||||
def _create_edit_ui(
|
|
||||||
self,
|
|
||||||
parent: ttk.Frame,
|
|
||||||
date: str,
|
|
||||||
dep: int,
|
|
||||||
anx: int,
|
|
||||||
slp: int,
|
|
||||||
app: int,
|
|
||||||
bup: int,
|
|
||||||
hydro: int,
|
|
||||||
gaba: int,
|
|
||||||
prop: int,
|
|
||||||
quet: int,
|
|
||||||
note: str,
|
|
||||||
dose_data: dict[str, str],
|
|
||||||
) -> dict[str, Any]:
|
|
||||||
"""Create UI layout for edit window with organized sections."""
|
|
||||||
vars_dict = {}
|
|
||||||
row = 0
|
|
||||||
|
|
||||||
# Header with entry date
|
|
||||||
header_frame = ttk.Frame(parent)
|
|
||||||
header_frame.grid(row=row, column=0, sticky="ew", pady=(0, 20))
|
|
||||||
header_frame.grid_columnconfigure(1, weight=1)
|
|
||||||
|
|
||||||
ttk.Label(
|
|
||||||
header_frame, text="Editing Entry for:", font=("TkDefaultFont", 12, "bold")
|
|
||||||
).grid(row=0, column=0, sticky="w")
|
|
||||||
|
|
||||||
vars_dict["date"] = tk.StringVar(value=str(date))
|
|
||||||
date_entry = ttk.Entry(
|
|
||||||
header_frame,
|
|
||||||
textvariable=vars_dict["date"],
|
|
||||||
font=("TkDefaultFont", 12),
|
|
||||||
width=15,
|
|
||||||
)
|
|
||||||
date_entry.grid(row=0, column=1, sticky="w", padx=(10, 0))
|
|
||||||
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
# Symptoms section
|
|
||||||
symptoms_frame = ttk.LabelFrame(
|
|
||||||
parent, text="Daily Symptoms (0-10 scale)", padding="15"
|
|
||||||
)
|
|
||||||
symptoms_frame.grid(row=row, column=0, sticky="ew", pady=(0, 15))
|
|
||||||
symptoms_frame.grid_columnconfigure(1, weight=1)
|
|
||||||
|
|
||||||
# Create symptom scales with better layout
|
|
||||||
symptoms = [
|
|
||||||
("Depression", "depression", dep),
|
|
||||||
("Anxiety", "anxiety", anx),
|
|
||||||
("Sleep Quality", "sleep", slp),
|
|
||||||
("Appetite", "appetite", app),
|
|
||||||
]
|
|
||||||
|
|
||||||
for i, (label, key, value) in enumerate(symptoms):
|
|
||||||
self._create_symptom_scale(symptoms_frame, i, label, key, value, vars_dict)
|
|
||||||
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
# Medications section
|
|
||||||
meds_frame = ttk.LabelFrame(parent, text="Medications Taken", padding="15")
|
|
||||||
meds_frame.grid(row=row, column=0, sticky="ew", pady=(0, 15))
|
|
||||||
meds_frame.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
# Create medicine checkboxes with better styling
|
|
||||||
med_vars = self._create_medicine_section(
|
|
||||||
meds_frame, bup, hydro, gaba, prop, quet
|
|
||||||
)
|
|
||||||
vars_dict.update(med_vars)
|
|
||||||
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
# Dose tracking section
|
|
||||||
dose_frame = ttk.LabelFrame(parent, text="Dose Tracking", padding="15")
|
|
||||||
dose_frame.grid(row=row, column=0, sticky="ew", pady=(0, 15))
|
|
||||||
dose_frame.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
dose_vars = self._create_dose_tracking(dose_frame, dose_data)
|
|
||||||
vars_dict.update(dose_vars)
|
|
||||||
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
# Notes section
|
|
||||||
notes_frame = ttk.LabelFrame(parent, text="Notes", padding="15")
|
|
||||||
notes_frame.grid(row=row, column=0, sticky="ew", pady=(0, 20))
|
|
||||||
notes_frame.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
vars_dict["note"] = tk.StringVar(value=str(note))
|
|
||||||
note_text = tk.Text(
|
|
||||||
notes_frame, height=4, wrap=tk.WORD, font=("TkDefaultFont", 10)
|
|
||||||
)
|
|
||||||
note_text.grid(row=0, column=0, sticky="ew")
|
|
||||||
note_text.insert(1.0, str(note))
|
|
||||||
vars_dict["note_text"] = note_text
|
|
||||||
|
|
||||||
# Add scrollbar for notes
|
|
||||||
note_scroll = ttk.Scrollbar(
|
|
||||||
notes_frame, orient="vertical", command=note_text.yview
|
|
||||||
)
|
|
||||||
note_scroll.grid(row=0, column=1, sticky="ns")
|
|
||||||
note_text.configure(yscrollcommand=note_scroll.set)
|
|
||||||
|
|
||||||
return vars_dict
|
|
||||||
|
|
||||||
def _create_symptom_scale(
|
def _create_symptom_scale(
|
||||||
self,
|
self,
|
||||||
parent: ttk.Frame,
|
parent: ttk.Frame,
|
||||||
@@ -733,91 +629,6 @@ class UIManager:
|
|||||||
scale.bind("<KeyRelease>", update_value_label)
|
scale.bind("<KeyRelease>", update_value_label)
|
||||||
update_value_label() # Set initial color
|
update_value_label() # Set initial color
|
||||||
|
|
||||||
def _create_enhanced_symptom_scale(
|
|
||||||
self,
|
|
||||||
parent: ttk.Frame,
|
|
||||||
row: int,
|
|
||||||
label: str,
|
|
||||||
key: str,
|
|
||||||
value: int,
|
|
||||||
vars_dict: dict[str, tk.IntVar],
|
|
||||||
) -> None:
|
|
||||||
"""Create enhanced symptom scale for new entry form (like edit window)."""
|
|
||||||
# Ensure value is properly converted
|
|
||||||
try:
|
|
||||||
value = int(float(value)) if value not in ["", None] else 0
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
value = 0
|
|
||||||
|
|
||||||
# Label
|
|
||||||
label_widget = ttk.Label(
|
|
||||||
parent, text=f"{label} (0-10):", font=("TkDefaultFont", 10, "bold")
|
|
||||||
)
|
|
||||||
label_widget.grid(row=row, column=0, sticky="w", padx=5, pady=8)
|
|
||||||
|
|
||||||
# Scale container
|
|
||||||
scale_container = ttk.Frame(parent)
|
|
||||||
scale_container.grid(row=row, column=1, sticky="ew", padx=(20, 5), pady=8)
|
|
||||||
scale_container.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
# Scale with value labels
|
|
||||||
scale_frame = ttk.Frame(scale_container)
|
|
||||||
scale_frame.grid(row=0, column=0, sticky="ew")
|
|
||||||
scale_frame.grid_columnconfigure(1, weight=1)
|
|
||||||
|
|
||||||
# Current value display
|
|
||||||
value_label = ttk.Label(
|
|
||||||
scale_frame,
|
|
||||||
text=str(value),
|
|
||||||
font=("TkDefaultFont", 12, "bold"),
|
|
||||||
foreground="#2E86AB",
|
|
||||||
width=3,
|
|
||||||
)
|
|
||||||
value_label.grid(row=0, column=0, padx=(0, 10))
|
|
||||||
|
|
||||||
# Scale widget
|
|
||||||
scale = ttk.Scale(
|
|
||||||
scale_frame,
|
|
||||||
from_=0,
|
|
||||||
to=10,
|
|
||||||
variable=vars_dict[key],
|
|
||||||
orient=tk.HORIZONTAL,
|
|
||||||
length=250, # Slightly smaller than edit window to fit better
|
|
||||||
)
|
|
||||||
scale.grid(row=0, column=1, sticky="ew")
|
|
||||||
|
|
||||||
# Scale labels (0, 5, 10)
|
|
||||||
labels_frame = ttk.Frame(scale_container)
|
|
||||||
labels_frame.grid(row=1, column=0, sticky="ew", pady=(5, 0))
|
|
||||||
|
|
||||||
ttk.Label(labels_frame, text="0", font=("TkDefaultFont", 8)).grid(
|
|
||||||
row=0, column=0, sticky="w"
|
|
||||||
)
|
|
||||||
labels_frame.grid_columnconfigure(1, weight=1)
|
|
||||||
ttk.Label(labels_frame, text="5", font=("TkDefaultFont", 8)).grid(
|
|
||||||
row=0, column=1
|
|
||||||
)
|
|
||||||
ttk.Label(labels_frame, text="10", font=("TkDefaultFont", 8)).grid(
|
|
||||||
row=0, column=2, sticky="e"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Update label when scale changes
|
|
||||||
def update_value_label(event=None):
|
|
||||||
current_val = vars_dict[key].get()
|
|
||||||
value_label.configure(text=str(current_val))
|
|
||||||
# Change color based on value
|
|
||||||
if current_val <= 3:
|
|
||||||
value_label.configure(foreground="#28A745") # Green for low/good
|
|
||||||
elif current_val <= 6:
|
|
||||||
value_label.configure(foreground="#FFC107") # Yellow for medium
|
|
||||||
else:
|
|
||||||
value_label.configure(foreground="#DC3545") # Red for high/bad
|
|
||||||
|
|
||||||
scale.bind("<Motion>", update_value_label)
|
|
||||||
scale.bind("<ButtonRelease-1>", update_value_label)
|
|
||||||
scale.bind("<KeyRelease>", update_value_label)
|
|
||||||
update_value_label() # Set initial color
|
|
||||||
|
|
||||||
def _create_enhanced_pathology_scale(
|
def _create_enhanced_pathology_scale(
|
||||||
self,
|
self,
|
||||||
parent: ttk.Frame,
|
parent: ttk.Frame,
|
||||||
@@ -927,153 +738,6 @@ class UIManager:
|
|||||||
update_value_label_pathology() # Set initial color
|
update_value_label_pathology() # Set initial color
|
||||||
|
|
||||||
def _create_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 medicine checkboxes with organized layout."""
|
|
||||||
vars_dict = {}
|
|
||||||
|
|
||||||
# Create a grid layout for medicines
|
|
||||||
medicines = [
|
|
||||||
("bupropion", bup, "Bupropion", "150/300 mg", "#E8F4FD"),
|
|
||||||
("hydroxyzine", hydro, "Hydroxyzine", "25 mg", "#FFF2E8"),
|
|
||||||
("gabapentin", gaba, "Gabapentin", "100 mg", "#F0F8E8"),
|
|
||||||
("propranolol", prop, "Propranolol", "10 mg", "#FCE8F3"),
|
|
||||||
("quetiapine", quet, "Quetiapine", "25 mg", "#E8F0FF"),
|
|
||||||
]
|
|
||||||
|
|
||||||
# Create medicine cards in a 2-column layout
|
|
||||||
for i, (key, value, name, dose, _bg_color) in enumerate(medicines):
|
|
||||||
row = i // 2
|
|
||||||
col = i % 2
|
|
||||||
|
|
||||||
# Medicine card frame
|
|
||||||
med_card = ttk.Frame(parent, relief="solid", borderwidth=1)
|
|
||||||
med_card.grid(row=row, column=col, sticky="ew", padx=5, pady=5)
|
|
||||||
parent.grid_columnconfigure(col, weight=1)
|
|
||||||
|
|
||||||
vars_dict[key] = tk.IntVar(value=int(value))
|
|
||||||
|
|
||||||
# Checkbox with medicine name
|
|
||||||
check_frame = ttk.Frame(med_card)
|
|
||||||
check_frame.pack(fill="x", padx=10, pady=8)
|
|
||||||
|
|
||||||
checkbox = ttk.Checkbutton(
|
|
||||||
check_frame,
|
|
||||||
text=f"{name} ({dose})",
|
|
||||||
variable=vars_dict[key],
|
|
||||||
style="Medicine.TCheckbutton",
|
|
||||||
)
|
|
||||||
checkbox.pack(anchor="w")
|
|
||||||
|
|
||||||
return vars_dict
|
|
||||||
|
|
||||||
def _create_dose_tracking(
|
|
||||||
self, parent: ttk.Frame, dose_data: dict[str, str]
|
|
||||||
) -> dict[str, Any]:
|
|
||||||
"""Create dose tracking interface."""
|
|
||||||
vars_dict = {}
|
|
||||||
|
|
||||||
# Create notebook for organized dose tracking
|
|
||||||
notebook = ttk.Notebook(parent)
|
|
||||||
notebook.pack(fill="both", expand=True)
|
|
||||||
|
|
||||||
medicines = [
|
|
||||||
("bupropion", "Bupropion"),
|
|
||||||
("hydroxyzine", "Hydroxyzine"),
|
|
||||||
("gabapentin", "Gabapentin"),
|
|
||||||
("propranolol", "Propranolol"),
|
|
||||||
("quetiapine", "Quetiapine"),
|
|
||||||
]
|
|
||||||
|
|
||||||
for med_key, med_name in medicines:
|
|
||||||
# Create tab for each medicine
|
|
||||||
tab_frame = ttk.Frame(notebook)
|
|
||||||
notebook.add(tab_frame, text=med_name)
|
|
||||||
|
|
||||||
# Configure tab layout
|
|
||||||
tab_frame.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
# Quick dose entry section
|
|
||||||
entry_frame = ttk.LabelFrame(tab_frame, text="Add New Dose", padding="10")
|
|
||||||
entry_frame.grid(row=0, column=0, sticky="ew", padx=10, pady=5)
|
|
||||||
entry_frame.grid_columnconfigure(1, weight=1)
|
|
||||||
|
|
||||||
ttk.Label(entry_frame, text="Dose amount:").grid(
|
|
||||||
row=0, column=0, sticky="w"
|
|
||||||
)
|
|
||||||
|
|
||||||
dose_entry_var = tk.StringVar()
|
|
||||||
vars_dict[f"{med_key}_entry_var"] = dose_entry_var
|
|
||||||
|
|
||||||
dose_entry = ttk.Entry(entry_frame, textvariable=dose_entry_var, width=15)
|
|
||||||
dose_entry.grid(row=0, column=1, sticky="w", padx=(10, 10))
|
|
||||||
|
|
||||||
# Quick dose buttons
|
|
||||||
quick_frame = ttk.Frame(entry_frame)
|
|
||||||
quick_frame.grid(row=0, column=2, sticky="w")
|
|
||||||
|
|
||||||
# Common dose amounts (customize per medicine)
|
|
||||||
quick_doses = self._get_quick_doses(med_key)
|
|
||||||
for i, dose in enumerate(quick_doses):
|
|
||||||
ttk.Button(
|
|
||||||
quick_frame,
|
|
||||||
text=dose,
|
|
||||||
width=8,
|
|
||||||
command=lambda d=dose, var=dose_entry_var: var.set(d),
|
|
||||||
).grid(row=0, column=i, padx=2)
|
|
||||||
|
|
||||||
# Take dose button
|
|
||||||
def create_take_dose_command(med_name, entry_var, med_key):
|
|
||||||
def take_dose():
|
|
||||||
self._take_dose(med_name, entry_var, med_key, vars_dict)
|
|
||||||
|
|
||||||
return take_dose
|
|
||||||
|
|
||||||
take_button = ttk.Button(
|
|
||||||
entry_frame,
|
|
||||||
text=f"Take {med_name}",
|
|
||||||
style="Accent.TButton",
|
|
||||||
command=create_take_dose_command(med_name, dose_entry_var, med_key),
|
|
||||||
)
|
|
||||||
take_button.grid(row=1, column=0, columnspan=3, pady=(10, 0), sticky="ew")
|
|
||||||
|
|
||||||
# Dose history section
|
|
||||||
history_frame = ttk.LabelFrame(
|
|
||||||
tab_frame, text="Today's Doses", padding="10"
|
|
||||||
)
|
|
||||||
history_frame.grid(row=1, column=0, sticky="ew", padx=10, pady=5)
|
|
||||||
history_frame.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
# Dose history display with fixed height to prevent excessive expansion
|
|
||||||
dose_text = tk.Text(
|
|
||||||
history_frame,
|
|
||||||
height=4, # Reduced height to fit better in scrollable window
|
|
||||||
wrap=tk.WORD,
|
|
||||||
font=("Consolas", 10),
|
|
||||||
state="normal", # Start enabled
|
|
||||||
)
|
|
||||||
dose_text.grid(row=0, column=0, sticky="ew")
|
|
||||||
|
|
||||||
# Store raw dose string in a variable
|
|
||||||
doses_str = dose_data.get(med_key, "")
|
|
||||||
dose_str_var = tk.StringVar(value=doses_str)
|
|
||||||
vars_dict[f"{med_key}_doses_str"] = dose_str_var
|
|
||||||
|
|
||||||
# Populate with existing doses
|
|
||||||
self._populate_dose_history(dose_text, dose_str_var.get())
|
|
||||||
|
|
||||||
vars_dict[f"{med_key}_doses_text"] = dose_text
|
|
||||||
|
|
||||||
# Scrollbar for dose history
|
|
||||||
dose_scroll = ttk.Scrollbar(
|
|
||||||
history_frame, orient="vertical", command=dose_text.yview
|
|
||||||
)
|
|
||||||
dose_scroll.grid(row=0, column=1, sticky="ns")
|
|
||||||
dose_text.configure(yscrollcommand=dose_scroll.set)
|
|
||||||
|
|
||||||
return vars_dict
|
|
||||||
|
|
||||||
def _create_medicine_section_dynamic(
|
|
||||||
self, parent: ttk.Frame, medicine_values: dict[str, int]
|
self, parent: ttk.Frame, medicine_values: dict[str, int]
|
||||||
) -> dict[str, tk.IntVar]:
|
) -> dict[str, tk.IntVar]:
|
||||||
"""Create medicine checkboxes dynamically."""
|
"""Create medicine checkboxes dynamically."""
|
||||||
@@ -1120,7 +784,7 @@ class UIManager:
|
|||||||
|
|
||||||
return vars_dict
|
return vars_dict
|
||||||
|
|
||||||
def _create_dose_tracking_dynamic(
|
def _create_dose_tracking(
|
||||||
self, parent: ttk.Frame, medicine_doses: dict[str, str]
|
self, parent: ttk.Frame, medicine_doses: dict[str, str]
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Create dose tracking interface dynamically."""
|
"""Create dose tracking interface dynamically."""
|
||||||
@@ -1398,9 +1062,33 @@ class UIManager:
|
|||||||
|
|
||||||
# Get note text from Text widget
|
# Get note text from Text widget
|
||||||
note_text_widget = vars_dict.get("note_text")
|
note_text_widget = vars_dict.get("note_text")
|
||||||
|
self.logger.debug(f"note_text_widget found: {note_text_widget is not None}")
|
||||||
|
self.logger.debug(f"vars_dict keys: {list(vars_dict.keys())}")
|
||||||
|
|
||||||
note_content = ""
|
note_content = ""
|
||||||
if note_text_widget:
|
if note_text_widget:
|
||||||
note_content = note_text_widget.get(1.0, tk.END).strip()
|
try:
|
||||||
|
note_content = note_text_widget.get(1.0, tk.END).strip()
|
||||||
|
self.logger.debug(f"Note content from widget: '{note_content}'")
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error getting note from text widget: {e}")
|
||||||
|
# Fallback to StringVar
|
||||||
|
note_var = vars_dict.get("note")
|
||||||
|
if note_var:
|
||||||
|
note_content = note_var.get()
|
||||||
|
self.logger.debug(
|
||||||
|
f"Note content from StringVar fallback: '{note_content}'"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Fallback to StringVar if note_text widget not found
|
||||||
|
note_var = vars_dict.get("note")
|
||||||
|
if note_var:
|
||||||
|
note_content = note_var.get()
|
||||||
|
self.logger.debug(f"Note content from StringVar: '{note_content}'")
|
||||||
|
else:
|
||||||
|
self.logger.error("No note widget or StringVar found!")
|
||||||
|
|
||||||
|
self.logger.debug(f"Final note_content: '{note_content}'")
|
||||||
|
|
||||||
# Extract dose data dynamically from all medicines
|
# Extract dose data dynamically from all medicines
|
||||||
dose_data = {}
|
dose_data = {}
|
||||||
|
|||||||
Reference in New Issue
Block a user