Files
Paddy d418f156fa German date display + optional street address for precise geocoding
- Date pickers (entry form + edit dialog) now display TT.MM.JJJJ instead of
  ISO (DATE_DISPLAY_FORMAT). Storage stays YYYY-MM-DD; parse_date() already
  accepted both formats, so existing data and the self-updater are unaffected.
- New optional "Straße" field (street + house number) in the entry form and
  edit dialog, backed by a new `street` CSV column. geocode_city() and
  GeocoderWorker.enqueue() gained a street parameter: when set, a full-address
  query is tried first for a much more precise map point, falling back
  automatically to the existing city/PLZ search if it doesn't resolve.
- Tab 2 and the entry queue show a Straße column; Tab 2 search now also
  matches on street.
- Fix: pandas turns a blank CSV cell into NaN even for a dtype=str column, so
  every existing (blank-street) row would have shown literal "nan" in Tab 2.
  DataStore._load now does street.fillna("") after every read.

Verified with a non-GUI test suite (date parsing, query construction, CSV
round-trip incl. the NaN case) and a full GUI build/drive test on Python
3.12/Tk 9. Docs updated (changelog, overview, architecture, data-model,
dev-notes, improvements).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 11:15:37 +02:00

163 lines
8.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
Notable changes to the app. Newest first.
## 2026-09-12 — German date display + optional street address for geocoding
- **Date fields now display `TT.MM.JJJJ`** (e.g. `12.09.2026`) instead of ISO,
in both the entry form and the edit dialog (`DATE_DISPLAY_FORMAT`). Storage on
disk is unchanged (`YYYY-MM-DD`) — `parse_date()` still accepts either format
when typed, so nothing about existing data changes.
- **New optional "Straße" field** (street + house number) on the entry form and
in the edit dialog, and a new `street` CSV column. When set, geocoding tries
the full address first for a much more precise map point, falling back to the
existing city/PLZ search if the address doesn't resolve — see
[overview.md](overview.md#geocoding-behaviour). `geocode_city()` and
`GeocoderWorker.enqueue()` both gained a `street` parameter.
- Tab 2 and the entry queue both show a **Straße** column; the Tab 2 search box
now also matches on street.
- Fixed a bug this surfaced immediately: pandas turns a **blank CSV cell into
`NaN`, even for a column forced to `dtype=str`** — every pre-existing row (all
blank on `street`) would have displayed the literal text `nan`. `DataStore._load`
now does `self.df["street"] = self.df["street"].fillna("")`. See
[dev-notes.md](dev-notes.md#pandas-turns-blank-csv-cells-into-nan-even-with-dtypestr).
- `find_duplicates` intentionally still ignores `street` (unchanged: date + city
+ PLZ only).
## 2026-09-07 — fix: right-click context menu instantly triggered its first item
On Linux the Tab 2 (and queue) right-click menu flashed and immediately ran
"Bearbeiten" / "Löschen", so entries couldn't be deleted. Cause: the menu was
bound to `<Button-3>` (press) and `finally: menu.grab_release()` dropped the
grab, so the following `<ButtonRelease-3>` selected the item under the cursor.
Fix: bind `<ButtonRelease-3>` (`<ButtonRelease-2>` on macOS), build each menu
once, and drop the premature `grab_release()`.
## 2026-09-07 — map tiles → Esri (OSM 403s local files)
The switch to `tiles="OpenStreetMap"` worked on the dev machine but the target
laptop's browser got **HTTP 403 "referer is required by tile usage policy"**
OSM's CDN blocks refererless requests, and a `karte.html` opened as `file://`
sends no `Referer`. Switched to **Esri "World Light Gray"** (base + labels
overlay, `server.arcgisonline.com`): no key, no `Referer` check, muted look
similar to the old positron. Constants `MAP_TILES` / `MAP_TILES_LABELS` /
`MAP_TILES_ATTR`.
## 2026-09-07 — install split for non-admin users
The target account has no sudo, so install is two scripts:
- `install-system.sh` admin runs once: `apt install python3-tk python3-venv git`.
- `install.sh` user runs, **no sudo**: checks the system packages, creates
`.venv` + installs `requirements.txt`, writes the `.desktop` menu entry. If a
package is missing and the account can't sudo, it prints the exact admin
command and stops.
## 2026-09-07 — one-command install + launcher
- `install.sh` Linux Mint setup: `.venv` + `requirements.txt`, and a
`.desktop` menu entry with correct absolute paths.
- `run.sh` launches the app from `.venv`; the menu entry calls this.
- `icon.png` bundled red-cross launcher/window icon (256×256); the app now
prefers this over the runtime-drawn one.
- `requirements.txt` **fully pinned** (direct + transitive), tested on
Python 3.12. `numpy` capped at 2.2.6 so it still installs on Python 3.10.
## 2026-09-07 — built-in self-update
New **Hilfe** menu:
- **Nach Update suchen** `git fetch` + count of new commits on the server.
- **Version…** shows the installed commit (`<hash> · <date>`).
On start, a quiet background check runs; if updates exist the status bar says so
and the menu item becomes "Update installieren (N verfügbar)".
Installing runs `git merge --ff-only` (fast-forward only never an automatic
merge), re-runs `pip install -r requirements.txt` if that file changed, then
restarts the app via `os.execv`. User data (`data/`) is git-ignored and
untouched. If the local checkout has diverged or the network is down, it shows a
clear message and does nothing.
Only active when the app runs from a **git clone** with `git` installed;
otherwise the menu just shows "Version: unbekannt". New `Updater` class,
`app.py`.
## 2026-09-07 — map tiles switched to OpenStreetMap
`folium.Map(tiles="CartoDB positron")` began showing an "API KEY REQUIRED"
watermark (Carto moved its basemaps behind a key). Switched to
`tiles="OpenStreetMap"` via a new `MAP_TILES` constant — no key required. OSM
standard tiles are more colourful than positron was; `MAP_TILES` makes swapping
the provider a one-line change.
## 2026-09-07 — UI/UX pass
A round of usability improvements aimed at the non-technical user
(see [improvements.md](improvements.md#uiux-review-2026-09-07)).
- **Larger UI font** (`UI_FONT_SIZE = 11`) applied to all default fonts, menus,
dialogs and the Treeview (taller rows).
- **DRK-red header bar** with the app name; window title shows the total count
("… · 142 Einsätze"); simple red-cross window icon drawn at runtime (also
written to `data/icon.png` for the launcher).
- **Status bar** is now colour-coded by severity (grey/green/orange/red), and
transient messages auto-clear after 8 s back to a neutral state; queue-count
messages stay put.
- **Tab 1:** more spacing in the form; PLZ field accepts digits only;
"+ Hinzufügen" is a solid button; explicit **"Auswahl entfernen"** button and
<kbd>Delete</kbd> key for queue rows; **"Warteschlange leeren"** now asks for
confirmation; **duplicate save shows a modal** (list + "trotzdem speichern?")
instead of a transient hint.
- **Tab 2:** the raw `lat`/`lon` columns are replaced by a single **"Karte"**
column (`✓` / red `fehlt`); active sort column shows a ▲/▼ arrow; the hint
line always shows the saved-entry count.
- **"Karte öffnen"** with no coordinates now shows a dialog, not just a status
line.
- **Window size & position** are remembered between sessions
(`data/window.json`).
## 2026-09-07 — data safety, robustness, easier input
Addressed the top three findings from [improvements.md](improvements.md).
### Data safety (`DataStore`)
- All writes (append / update / delete) now rebuild the full DataFrame and go
through `_save_csv`: **rotating backup** to `data/backups/` (startup + before
every change, keep 20, skip if unchanged) then **atomic write**
(`tmp` + `fsync` + `os.replace`).
- `orte.csv` missing / empty (`EmptyDataError`) / unreadable now falls back to an
empty table or the newest backup instead of crashing.
### Geocoder robustness (`GeocoderWorker`, `geocode_city`)
- Each queue item runs inside `try/except`; a failing lookup or callback logs a
traceback and the worker keeps going (previously an unexpected error killed the
thread and silently froze all further geocoding).
- `geocode_city` raises `GeocodingUnavailable` when every query failed on a
service/network error. After 3 in a row the app shows a one-time
"Standortdienst nicht erreichbar" dialog; entries still save without
coordinates.
### Easier, safer input
- Date fields (entry form + edit dialog) are now `ttkbootstrap.DateEntry`
calendar pickers, validated/normalized to ISO by `parse_date()` (also accepts
`TT.MM.JJJJ`). Invalid dates are rejected with a dialog.
- Edit dialog has manual **Breitengrad / Längengrad** fields for fixing
coordinates by hand.
- Tab 2: rows without coordinates shown in red, "Nur ohne Koordinaten" filter,
count in the hint line, right-click **Koordinaten suchen**.
### Housekeeping
- `git init` + `.gitignore`.
- Rotating log file at `data/app.log` (`_setup_logging`).
- Shared helpers `filter_locations` / `split_city_plz` / `parse_coord` replace
duplicated combobox code.
- Config constants: `GEOCODE_REGIONS`, `MAP_DEFAULT_CENTER`, `MAP_DEFAULT_ZOOM`,
`MAX_BACKUPS`.
- `generate_map` fits the view to the markers.
### Verification
Non-GUI smoke tests (helpers, `DataStore` backup/atomic/recovery, geocoder
resilience) pass. The GUI now *can* be built and driven on the dev Mac via a
Homebrew Python with Tk 9 — see [dev-notes.md](dev-notes.md).