v1.9.1: PNG Material Design icons — 28 icons, dark/light theme, HiDPI, graceful Unicode fallback
- 56 PNG icons (28 unique × 2 color variants) from Material Design Icons (round style, 96×96px) - core/icons.py: ctk_icon(), make_icon_button(), reconfigure_icon_button() with CTkImage cache - Updated 15 GUI files: app.py, sidebar.py, server_dialog.py, all tabs - build.py: auto-include assets/icons/ in PyInstaller bundle, patch rollover at 99→minor+1 - tools/download_icons.py: icon download script - Automatic dark↔light theme switching via CTkImage dual-image support Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
59
build.py
59
build.py
@@ -36,7 +36,13 @@ def auto_bump_version() -> str:
|
||||
sys.exit(1)
|
||||
|
||||
major, minor, patch = int(match.group(1)), int(match.group(2)), int(match.group(3))
|
||||
new_patch = patch + 1
|
||||
|
||||
# Patch grows up to 99, then minor+1 and patch resets to 1
|
||||
if patch >= 99:
|
||||
minor += 1
|
||||
new_patch = 1
|
||||
else:
|
||||
new_patch = patch + 1
|
||||
new_version = f"{major}.{minor}.{new_patch}"
|
||||
|
||||
content = re.sub(
|
||||
@@ -111,6 +117,13 @@ def build():
|
||||
"--add-data", f"core/encryption.py{os.pathsep}core",
|
||||
]
|
||||
|
||||
# PNG icons for GUI (Material Design)
|
||||
icons_dir = os.path.join(PROJECT_DIR, "assets", "icons")
|
||||
if os.path.isdir(icons_dir):
|
||||
cmd_parts.extend(["--add-data", f"assets/icons{os.pathsep}assets/icons"])
|
||||
else:
|
||||
print("WARNING: assets/icons/ not found, building without PNG icons")
|
||||
|
||||
# Icon
|
||||
icon_path = os.path.join(PROJECT_DIR, "assets", "icon.ico")
|
||||
if os.path.exists(icon_path):
|
||||
@@ -194,6 +207,47 @@ def _get_gitea_auth() -> dict:
|
||||
_GITEA_API = "https://git.sensey24.ru/api/v1/repos/aibot777/server-manager"
|
||||
|
||||
|
||||
def _generate_changelog() -> str:
|
||||
"""Generate changelog from git commits since previous tag."""
|
||||
try:
|
||||
# Get all tags sorted by semver
|
||||
raw = subprocess.check_output(
|
||||
["git", "tag", "--list", "v*"],
|
||||
text=True, stderr=subprocess.DEVNULL,
|
||||
).strip()
|
||||
tags = [t for t in raw.splitlines() if re.match(r'^v\d+\.\d+\.\d+$', t)]
|
||||
tags.sort(key=lambda t: tuple(int(x) for x in t[1:].split(".")))
|
||||
|
||||
current_tag = f"v{__version__}"
|
||||
# Find previous tag (exclude current if it exists)
|
||||
prev_tags = [t for t in tags if t != current_tag]
|
||||
if prev_tags:
|
||||
prev_tag = prev_tags[-1]
|
||||
log_range = f"{prev_tag}..HEAD"
|
||||
else:
|
||||
log_range = "HEAD~20..HEAD"
|
||||
|
||||
# Get commits
|
||||
raw_log = subprocess.check_output(
|
||||
["git", "log", log_range, "--oneline", "--no-merges"],
|
||||
text=True, stderr=subprocess.DEVNULL,
|
||||
).strip()
|
||||
|
||||
if not raw_log:
|
||||
return f"Release {current_tag}"
|
||||
|
||||
# Format: strip commit hash, keep message
|
||||
lines = []
|
||||
for line in raw_log.splitlines():
|
||||
parts = line.split(" ", 1)
|
||||
if len(parts) == 2:
|
||||
lines.append(f"- {parts[1]}")
|
||||
return f"## What's New in {current_tag}\n\n" + "\n".join(lines)
|
||||
except Exception as exc:
|
||||
print(f"Changelog generation failed: {exc}")
|
||||
return f"Release v{__version__}"
|
||||
|
||||
|
||||
def publish_gitea_release(exe_path: str):
|
||||
"""Create a Gitea release and upload the exe as asset."""
|
||||
auth = _get_gitea_auth()
|
||||
@@ -203,13 +257,14 @@ def publish_gitea_release(exe_path: str):
|
||||
|
||||
tag = f"v{__version__}"
|
||||
filename = os.path.basename(exe_path)
|
||||
changelog = _generate_changelog()
|
||||
|
||||
# Create release
|
||||
try:
|
||||
data = json.dumps({
|
||||
"tag_name": tag,
|
||||
"name": tag,
|
||||
"body": f"Release {tag}",
|
||||
"body": changelog,
|
||||
}).encode()
|
||||
req = urllib.request.Request(
|
||||
f"{_GITEA_API}/releases",
|
||||
|
||||
Reference in New Issue
Block a user