diff --git a/photo_tagger.py b/photo_tagger.py index dc1274a..7e116cc 100644 --- a/photo_tagger.py +++ b/photo_tagger.py @@ -2782,6 +2782,7 @@ class PhotoTagger: match_vars = [] identified_faces_per_person = {} # Track which faces were identified for each person checkbox_states_per_person = {} # Track checkbox states for each person (unsaved selections) + original_checkbox_states_per_person = {} # Track original/default checkbox states for comparison def on_confirm_matches(): nonlocal identified_count, current_matched_index, identified_faces_per_person @@ -2832,9 +2833,13 @@ class PhotoTagger: for person_id in set(match['person_id'] for match in matches_for_this_person if match['person_id']): self._update_person_encodings(person_id) - # Clear checkbox states for this person after saving - if matched_id in checkbox_states_per_person: - del checkbox_states_per_person[matched_id] + # After saving, set original states to the current UI states so there are no unsaved changes + current_snapshot = {} + for match, var in zip(matches_for_this_person, match_vars): + unique_key = f"{matched_id}_{match['unidentified_id']}" + current_snapshot[unique_key] = var.get() + checkbox_states_per_person[matched_id] = dict(current_snapshot) + original_checkbox_states_per_person[matched_id] = dict(current_snapshot) def on_skip_current(): nonlocal current_matched_index @@ -2855,8 +2860,19 @@ class PhotoTagger: update_display() def has_unsaved_changes(): - """Check if there are any unsaved changes in checkbox_states_per_person""" - return len(checkbox_states_per_person) > 0 + """Check if there are any unsaved changes by comparing current states with original states""" + for person_id, current_states in checkbox_states_per_person.items(): + if person_id in original_checkbox_states_per_person: + original_states = original_checkbox_states_per_person[person_id] + # Check if any checkbox state differs from its original state + for key, current_value in current_states.items(): + if key not in original_states or original_states[key] != current_value: + return True + else: + # If person has current states but no original states, there are changes + if any(current_states.values()): + return True + return False def on_quit_auto_match(): nonlocal window_destroyed @@ -3003,7 +3019,10 @@ class PhotoTagger: save_btn.config(text="💾 Save Changes") def save_current_checkbox_states(): - """Save current checkbox states for the current person""" + """Save current checkbox states for the current person. + Note: Do NOT modify original states here to avoid false positives + when a user toggles and reverts a checkbox. + """ if current_matched_index < len(matched_ids) and match_vars: current_matched_id = matched_ids[current_matched_index] matches_for_current_person = matches_by_matched[current_matched_id] @@ -3015,9 +3034,11 @@ class PhotoTagger: # Save current checkbox states for this person for i, (match, var) in enumerate(zip(matches_for_current_person, match_vars)): unique_key = f"{current_matched_id}_{match['unidentified_id']}" - checkbox_states_per_person[current_matched_id][unique_key] = var.get() + current_value = var.get() + checkbox_states_per_person[current_matched_id][unique_key] = current_value + if self.verbose >= 2: - print(f"DEBUG: Saved state for person {current_matched_id}, face {match['unidentified_id']}: {var.get()}") + print(f"DEBUG: Saved state for person {current_matched_id}, face {match['unidentified_id']}: {current_value}") def update_display(): nonlocal current_matched_index @@ -3137,14 +3158,23 @@ class PhotoTagger: match_vars.append(match_var) + # Capture original state at render time (once per person per face) + if matched_id not in original_checkbox_states_per_person: + original_checkbox_states_per_person[matched_id] = {} + if unique_key not in original_checkbox_states_per_person[matched_id]: + original_checkbox_states_per_person[matched_id][unique_key] = match_var.get() + # Add callback to save state immediately when checkbox changes def on_checkbox_change(var, person_id, face_id): unique_key = f"{person_id}_{face_id}" if person_id not in checkbox_states_per_person: checkbox_states_per_person[person_id] = {} - checkbox_states_per_person[person_id][unique_key] = var.get() + + current_value = var.get() + checkbox_states_per_person[person_id][unique_key] = current_value + if self.verbose >= 2: - print(f"DEBUG: Checkbox changed for person {person_id}, face {face_id}: {var.get()}") + print(f"DEBUG: Checkbox changed for person {person_id}, face {face_id}: {current_value}") # Bind the callback to the variable match_var.trace('w', lambda *args: on_checkbox_change(match_var, matched_id, match['unidentified_id']))