Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,6 @@ node_modules/
.nyc_output/

dist_clean/

# Agenten-interne Loop-Statusschnappschuesse (GITHUB-POLICY.md SS3, T-20260926-510472849)
TASKPLAN_STATUS_*.md
11 changes: 8 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).

## [Unreleased]

## [1.0.7] - 2026-09-26

### Behoben / Fixed (Store-Icon weißer Rand — T-20260820-729932431)
- **Store-Kachel-Icons mit sichtbarem weißen Rand (`store_assets/Square44x44Logo.png`, `Square150x150Logo.png`, `Square310x310Logo.png`, `StoreLogo.png`, `Wide310x150Logo.png`)**: Diese Dateien hatten trotz RGBA-Modus einen opaken (nicht transparenten) Canvas-Hintergrund gebacken (Alpha 255 statt 0 rund um das Motiv, bei `Wide310x150Logo.png` im eingebetteten 150px-Mittelfeld) — sichtbar als weißer Kasten/Halo um das Icon-Motiv in Kachel, Startmenü, Taskleiste und Store-Listing.
- **Nachreview (merge-reviewer, claude-opus, Commit `aee6401`) fand einen Mangel** in einem ersten, per Direkt-Push auf `master` eingespielten Versuch (in 1.0.6 nicht mehr zurückgenommen, siehe unten): Die dort verwendeten Ersatzdateien (`icon_44x44.png` u. a.) zeigen eine ANDERE Gestaltung (gerahmte Variante mit cyanfarbenem Rahmen und weißer Sichel am Rand, kleineres Motiv) statt des ursprünglichen Vollflächen-Motivs — und `Wide310x150Logo.png` blieb dabei unentdeckt defekt.
- **Korrigierter Fix (dieser Release):** Freistellung des ursprünglichen Vollflächen-Motivs direkt aus den Store-Kacheln vor `aee6401` per Flood-Fill-Matting (nur der mit dem Canvas-Rand verbundene Hintergrund wird transparent, das Motiv selbst bleibt unangetastet) mit Un-Premultiply gegen den Weiß-Hintergrund, damit kein heller Fransensaum an der Kante zurückbleibt. Motiv unverändert (keine Neugestaltung), nur echte, weiche Transparenz statt gebackenem Hintergrund. `icon_310x150.png` ist ein separates Marketing-Banner (nicht vom AppxManifest referenziert) und bleibt unverändert. Regressionstest `test_store_tiles_have_transparent_corners` ergänzt. Verifiziert per Kontaktbogen (5 Größen × Weiß/Schwarz/Grau/Akzentgrün): kein Halo, kein Fransensaum, keine hellen Randflächen. Per Pull Request gegen `master` (kein Direkt-Push).

## [1.0.6] - 2026-09-26

### Behoben / Fixed (Kontextmenü, Editor-Dirty-Flag, Qt-Übersetzung — T-20260926-912169808)
Expand All @@ -14,9 +21,7 @@ Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.1.0/).
- **Speichern/Verwerfen-Dialog auf Englisch in der deutschen Version (`src/main.py`)**: Kein Qt-eigener Übersetzer installiert. `QTranslator` mit `qtbase_<lang>.qm` ergänzt (unabhängig von der App-eigenen `TranslationSystem`, kein Overwrite).
- **Mehrfach-Umbenennen/Diff/Einstellungen stürzen im Quellstart ab (`src/main.py`, `ExplorerPro.spec`)**: `translator.py` (Projektwurzel) fehlte auf `sys.path`; Spec um `pathex`/`datas` für Projektwurzel und `locales/` ergänzt.
- **9 neue automatisierte Regressionstests** (`tests/test_context_menu_actions.py`), Vollsuite 359 passed / 2 skipped. Review/Merge als zweites Modell: Repo `file-bricks/ExplorerPro#1`, Squash `264aa6eae60055f1ffb4ff041025920738c6ead2`.

### Behoben / Fixed (Store-Icon weißer Rand — T-20260820-729932431)
- **Store-Kachel-Icons mit sichtbarem weißen Rand (`store_assets/Square44x44Logo.png`, `Square150x150Logo.png`, `Square310x310Logo.png`, `StoreLogo.png`)**: Diese vier Dateien hatten trotz RGBA-Modus einen opaken (nicht transparenten) Canvas-Hintergrund gebacken (Alpha 255 an den Ecken statt 0) — sichtbar als weißer Kasten/Halo um das Icon-Motiv in Kachel, Startmenü und Store-Listing. Die im selben Ordner bereits korrekt transparenten Gegenstücke gleicher Größe und gleichen Motivs (`icon_44x44.png`, `icon_150x150.png`, `icon_310x310.png`, `icon_50x50.png`) haben die vier defekten Dateien ersetzt — Motiv unverändert (kein Redesign), nur echte Transparenz statt gebackenem Hintergrund. `Wide310x150Logo.png` war bereits korrekt; `icon_310x150.png` ist ein separates Marketing-Banner (nicht vom AppxManifest referenziert) und unverändert. Verifiziert per Kontaktbogen auf Weiß/Schwarz/Grau/Akzentgrün (kein Halo, keine hellen Ränder auf allen vier Hintergründen).
- **Bekannter Mangel dieses Releases:** Der ebenfalls in 1.0.6 enthaltene Icon-Fix-Versuch (direkt gepusht, `aee6401`) hatte das falsche Motiv und einen unentdeckt gebliebenen Defekt in `Wide310x150Logo.png` — die Store-Submission dieser Version läuft dennoch durch, weil die Kontextmenü-Fixes ankommen sollen; der korrigierte Icon-Fix folgt in 1.0.7.

### Behoben / Fixed (Bugsearch 2026-09-26)
- **Batch-Renamer, Kaskadierende Kollisionserkennung, Windows-Gerätenamens-Schutz und Nummerierungs-Affix-Integrität (`src/core/batch_rename_service.py`)**:
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
name: ExplorerPro
type: project-docs
profile: STANDARD
version: 1.0.6
version: 1.0.7
created: 2026-07-22
updated: 2026-09-26
reason_last_change: "T-20260926-912169808: Kontextmenü-Tags/Metadaten, Editor-Dirty-Flag (modificationChanged), qtbase-Übersetzung, 359 Tests"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
[![Umbrella: open--bricks](https://img.shields.io/badge/umbrella-open--bricks-blue.svg)](https://github.com/open-bricks)
[![Microsoft Store](https://img.shields.io/badge/Microsoft%20Store-Live-0078D7.svg?logo=windows)](https://apps.microsoft.com/detail/9P0X52WSHZ3Q)
[![LLM-Ready: llms.txt](https://img.shields.io/badge/LLM--Ready-llms.txt-success.svg)](llms.txt)
[![Version: 1.0.6](https://img.shields.io/badge/version-1.0.6-orange.svg)](CHANGELOG.md)
[![Version: 1.0.7](https://img.shields.io/badge/version-1.0.7-orange.svg)](CHANGELOG.md)
[![Last Checked](https://img.shields.io/badge/Last--Checked-2026--09--26-blue?style=flat-square)](CHANGELOG.md)

> [!NOTE]
Expand Down
2 changes: 1 addition & 1 deletion README_de.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
[![Dachverband: open--bricks](https://img.shields.io/badge/Dachverband-open--bricks-blue.svg)](https://github.com/open-bricks)
[![Microsoft Store](https://img.shields.io/badge/Microsoft%20Store-Live-0078D7.svg?logo=windows)](https://apps.microsoft.com/detail/9P0X52WSHZ3Q)
[![LLM-Ready: llms.txt](https://img.shields.io/badge/LLM--Ready-llms.txt-success.svg)](llms.txt)
[![Version: 1.0.6](https://img.shields.io/badge/Version-1.0.6-orange.svg)](CHANGELOG.md)
[![Version: 1.0.7](https://img.shields.io/badge/Version-1.0.7-orange.svg)](CHANGELOG.md)
[![Stand](https://img.shields.io/badge/Stand-2026--09--26-blue?style=flat-square)](CHANGELOG.md)

> [!NOTE]
Expand Down
68 changes: 0 additions & 68 deletions TASKPLAN_STATUS_2026-09-17_1324-tasksolver-attempt3.md

This file was deleted.

Binary file added _review/T-20260820-kontaktbogen.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ License: AGPL-3.0
Microsoft Store Identity: Geiger.ExplorerPro (Store-ID: 9P0X52WSHZ3Q)

Last-checked: 2026-09-26
Version: 1.0.6
Version: 1.0.7

## Search Phrases

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "explorerpro"
version = "1.0.6"
version = "1.0.7"
description = "Datei-Explorer-Suite mit Editor, PDF-Viewer und Datenanalyse"
authors = [{ name = "Lukas Geiger", email = "support@lukasgeiger.com" }]
requires-python = ">=3.10"
Expand Down
98 changes: 98 additions & 0 deletions scripts/defringe_store_tile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""Freistellen: entfernt einen naeher-am-weissen Canvas-Hintergrund liegenden,
mit dem Bild verbundenen Bereich per Flood-Fill und entfernt dabei per
Un-Premultiply auch den weissen Fransen-/Halo-Saum an den Kanten.
Motiv bleibt unveraendert; nur Hintergrund/Rand wird transparent."""
import sys, math
from collections import deque
from PIL import Image


def defringe(path, out_path, bg=None, bg_thresh=60):
im = Image.open(path).convert("RGBA")
w, h = im.size
px = im.load()

if bg is None:
# Referenz-Hintergrund aus den vier Ecken (falls dort opak) oder Default-Weiss.
samples = []
for cx, cy in ((0, 0), (w - 1, 0), (0, h - 1), (w - 1, h - 1)):
r, g, b, a = px[cx, cy]
if a > 0:
samples.append((r, g, b))
if samples:
bg = tuple(sum(c[i] for c in samples) / len(samples) for i in range(3))
else:
bg = (248.0, 247.0, 247.0)

def dist(c):
return math.sqrt(sum((c[i] - bg[i]) ** 2 for i in range(3)))

def passable(x, y):
r, g, b, a = px[x, y]
if a == 0:
return True, 0.0
d = dist((r, g, b))
if d < bg_thresh:
return True, d
return False, None

visited = [[False] * w for _ in range(h)]
dist_map = [[0.0] * w for _ in range(h)]
q = deque()

def seed(x, y):
if not visited[y][x]:
ok, d = passable(x, y)
if ok:
visited[y][x] = True
dist_map[y][x] = d
q.append((x, y))

for x in range(w):
seed(x, 0)
seed(x, h - 1)
for y in range(h):
seed(0, y)
seed(w - 1, y)

while q:
x, y = q.popleft()
for nx, ny in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
if 0 <= nx < w and 0 <= ny < h and not visited[ny][nx]:
ok, d = passable(nx, ny)
if ok:
visited[ny][nx] = True
dist_map[ny][nx] = d
q.append((nx, ny))

out = Image.new("RGBA", (w, h))
outpx = out.load()
feather = bg_thresh
for y in range(h):
for x in range(w):
r, g, b, a = px[x, y]
if visited[y][x]:
d = dist_map[y][x]
alpha = int(round(255 * min(1.0, d / feather)))
if alpha <= 0:
outpx[x, y] = (0, 0, 0, 0)
else:
af = alpha / 255.0
nr = (r - (1 - af) * bg[0]) / af
ng = (g - (1 - af) * bg[1]) / af
nb = (b - (1 - af) * bg[2]) / af
nr = max(0, min(255, round(nr)))
ng = max(0, min(255, round(ng)))
nb = max(0, min(255, round(nb)))
outpx[x, y] = (nr, ng, nb, alpha)
else:
outpx[x, y] = (r, g, b, 255)
out.save(out_path, "PNG")
return bg


if __name__ == "__main__":
src, dst = sys.argv[1], sys.argv[2]
thresh = float(sys.argv[3]) if len(sys.argv) > 3 else 60
used_bg = defringe(src, dst, bg_thresh=thresh)
print("bg used:", used_bg, "->", dst)
Binary file modified store_assets/Square150x150Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified store_assets/Square310x310Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified store_assets/Square44x44Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified store_assets/StoreLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified store_assets/Wide310x150Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion store_package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publisher": "CN=52596601-BAB4-4F3F-B182-E8F3F273B202",
"publisher_display": "Geiger",
"identity_name": "Geiger.ExplorerPro",
"version": "1.0.6.0",
"version": "1.0.7.0",
"description": "Lokale Explorer-Suite mit Mehrtab-Dateibrowser, Vorschau, Datenschutzprüfung, Duplikatsuche und Offline-Workflow.",
"executable": "ExplorerPro.exe",
"capabilities": "runFullTrust",
Expand Down
36 changes: 36 additions & 0 deletions tests/test_assets_and_icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,42 @@ def test_store_assets_integrity():
assert img.size == size, f"{name} size {img.size} != {size}"


def test_store_tiles_have_transparent_corners():
"""Regression fuer T-20260820-729932431: die vom AppxManifest referenzierten
Kacheln duerfen keinen gebackenen opaken Hintergrund haben (weisser Halo)."""
store_dir = REPO_ROOT / "store_assets"
manifest_tiles = [
"Square44x44Logo.png",
"Square150x150Logo.png",
"Square310x310Logo.png",
"StoreLogo.png",
]
for name in manifest_tiles:
with Image.open(store_dir / name).convert("RGBA") as img:
w, h = img.size
corner_alpha = img.getpixel((0, 0))[3]
assert corner_alpha < 30, (
f"{name}: Ecke (0,0) ist fast opak (Alpha {corner_alpha}) -- "
"gebackener Hintergrund statt Transparenz (weisser Halo)."
)

# Wide310x150Logo bettet das Motiv mittig in ein 310x150-Canvas ein;
# sowohl der aeussere Rand als auch das eingebettete Quadrat muessen
# an ihren Ecken transparent sein (der Halo im Mittelfeld war 2026-09-26
# zunaechst unentdeckt geblieben, weil nur die Aussen-Ecken geprueft wurden).
with Image.open(store_dir / "Wide310x150Logo.png").convert("RGBA") as wide:
w, h = wide.size
assert wide.getpixel((0, 0))[3] < 30, "Wide310x150Logo: aeussere Ecke nicht transparent"
square_left = (w - h) // 2
for x_offset in (2, h - 3):
for y_offset in (2, h - 3):
a = wide.getpixel((square_left + x_offset, y_offset))[3]
assert a < 30, (
f"Wide310x150Logo: Ecke des eingebetteten Quadrats bei "
f"({square_left + x_offset},{y_offset}) ist fast opak (Alpha {a})."
)


def test_app_icon_loader_returns_valid_icon():
"""Verify src.main.load_app_icon() returns a valid, non-null QIcon."""
from PySide6.QtWidgets import QApplication
Expand Down
8 changes: 4 additions & 4 deletions tests/test_metadata_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def test_llms_txt_structure():
assert "file-bricks/ExplorerPro" in content
assert "PySide6" in content
assert "Last-checked: 2026-09-26" in content
assert "1.0.6" in content
assert "1.0.7" in content
assert "ci.yml" in content


Expand Down Expand Up @@ -267,9 +267,9 @@ def test_version_parity():
claude_text = (REPO_ROOT / "CLAUDE.md").read_text(encoding="utf-8")
changelog_text = (REPO_ROOT / "CHANGELOG.md").read_text(encoding="utf-8")

assert 'version = "1.0.6"' in pyproject_text
assert "version: 1.0.6" in claude_text
assert "## [1.0.6]" in changelog_text
assert 'version = "1.0.7"' in pyproject_text
assert "version: 1.0.7" in claude_text
assert "## [1.0.7]" in changelog_text


def test_readme_18_point_navigation_parity():
Expand Down
Loading