diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 8f051335..00000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**complete the following information):** - - Device: [e.g. Redmi 5A] - - OS: [e.g. MIUI 11] - - Android Version [e.g. Android 10] - -**logcat output/logcat.txt(if applicable)** - - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..5e0c6688 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,87 @@ +name: Bug report +description: Report a reproducible problem in Termix +title: "[Bug] " +labels: + - bug +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to report a bug. + + Please provide enough detail for us to reproduce and diagnose the issue. + + - type: textarea + id: summary + attributes: + label: Summary + description: Describe the bug clearly and concisely. + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: List the exact steps needed to reproduce the issue. + placeholder: | + 1. Open ... + 2. Tap or run ... + 3. Observe ... + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected behavior + description: Describe what you expected to happen. + validations: + required: true + + - type: textarea + id: actual + attributes: + label: Actual behavior + description: Describe what actually happened instead. + validations: + required: true + + - type: textarea + id: environment + attributes: + label: Environment + description: Provide the environment details used when the bug occurred. + value: | + - Device: + - ROM / OS: + - Android version: + - Termix version: + - Install source: + validations: + required: true + + - type: textarea + id: logs + attributes: + label: Logs + description: Paste any relevant logcat output, stack trace, or error message. + render: shell + validations: + required: false + + - type: textarea + id: media + attributes: + label: Screenshots or screen recordings + description: Add links or short notes for any screenshots or recordings that help explain the issue. + validations: + required: false + + - type: textarea + id: additional + attributes: + label: Additional context + description: Add any other context that may help reproduce or diagnose the problem. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..52324e97 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Termix README + url: https://github.com/jeffusion/Termix#readme + about: Read the project overview, build instructions, and screenshots before opening an issue. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7d..00000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..2e284ba0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,60 @@ +name: Feature request +description: Suggest an improvement or new capability for Termix +title: "[Feature] " +labels: + - enhancement +body: + - type: markdown + attributes: + value: | + Thanks for suggesting an improvement for Termix. + + Please explain the problem, proposed solution, and why it matters. + + - type: textarea + id: problem + attributes: + label: Problem statement + description: Describe the problem or limitation you are trying to solve. + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed solution + description: Describe the behavior, workflow, or feature you would like to see. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Describe any alternative solutions, workarounds, or designs you have considered. + validations: + required: false + + - type: textarea + id: use-case + attributes: + label: Use case + description: Explain why this would be valuable for users or contributors. + validations: + required: true + + - type: checkboxes + id: checks + attributes: + label: Before submitting + options: + - label: I searched the existing issues to avoid creating a duplicate request. + required: true + + - type: textarea + id: additional + attributes: + label: Additional context + description: Add any mockups, screenshots, references, or extra context here. + validations: + required: false diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..851327b3 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,16 @@ +## Summary + +- + +## Testing + +- [ ] Not run +- [ ] Built locally +- [ ] Tested on device/emulator + +## Checklist + +- [ ] My changes are scoped and relevant to this PR +- [ ] I updated documentation when needed +- [ ] I verified the affected behavior locally +- [ ] I did not include unrelated changes diff --git a/scripts/generate_launcher_icons.py b/scripts/generate_launcher_icons.py index 0b2faa4a..b5d0a168 100755 --- a/scripts/generate_launcher_icons.py +++ b/scripts/generate_launcher_icons.py @@ -3,6 +3,7 @@ import argparse from pathlib import Path +from typing import cast from PIL import Image @@ -26,6 +27,11 @@ BACKGROUND_COLOR = (12, 15, 16, 255) FOREGROUND_SCALE = 0.80 MONOCHROME_SCALE = 0.55 +BACKGROUND_DISTANCE_THRESHOLD = 28 + + +def get_rgba_pixel(image: Image.Image, x: int, y: int) -> tuple[int, int, int, int]: + return cast(tuple[int, int, int, int], image.getpixel((x, y))) def render_contain( @@ -45,23 +51,59 @@ def render_contain( def build_monochrome_mask(source: Image.Image) -> Image.Image: - rgba = source.load() monochrome = Image.new("RGBA", source.size, (255, 255, 255, 0)) - mono_pixels = monochrome.load() - for y in range(source.height): - for x in range(source.width): - r, g, b, a = rgba[x, y] + edge_samples: list[tuple[int, int, int]] = [] + width = source.width + height = source.height + + for x in range(width): + for y in (0, height - 1): + r, g, b, a = get_rgba_pixel(source, x, y) + if a > 0: + edge_samples.append((r, g, b)) + + for y in range(height): + for x in (0, width - 1): + r, g, b, a = get_rgba_pixel(source, x, y) + if a > 0: + edge_samples.append((r, g, b)) + + background_color: tuple[int, int, int] | None = None + if edge_samples: + red, green, blue = ( + round(sum(channel) / len(edge_samples)) for channel in zip(*edge_samples) + ) + background_color = (red, green, blue) + + for y in range(height): + for x in range(width): + r, g, b, a = get_rgba_pixel(source, x, y) if a == 0: continue - luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b - if g > 110 and g > r + 25 and g > b + 20 and luminance > 70: - mono_pixels[x, y] = (255, 255, 255, 255) + if background_color is None: + monochrome.putpixel((x, y), (255, 255, 255, 255)) + continue + + color_distance = sum( + abs(channel - background_channel) + for channel, background_channel in zip((r, g, b), background_color) + ) + if color_distance >= BACKGROUND_DISTANCE_THRESHOLD: + monochrome.putpixel((x, y), (255, 255, 255, 255)) bbox = monochrome.getbbox() if bbox is None: - raise RuntimeError("Unable to derive monochrome launcher icon from source logo") + alpha_mask = source.getchannel("A") + bbox = alpha_mask.getbbox() + if bbox is None: + raise RuntimeError( + "Unable to derive monochrome launcher icon from source logo" + ) + + monochrome = Image.new("RGBA", source.size, (255, 255, 255, 0)) + monochrome.putalpha(alpha_mask) return monochrome.crop(bbox)