diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..c1cfda1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,82 @@ +name: Bug report +description: Something behaves incorrectly in WaveFlow for Android. +labels: ["type: fix", "needs triage"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to report this. A precise report gets fixed + much faster than a vague one. + + **Security issue?** Don't file it here — see + [SECURITY.md](https://github.com/InstaZDLL/waveflow-android/blob/main/.github/SECURITY.md). + + - type: textarea + id: what-happened + attributes: + label: What happened + description: What you saw, and what you expected instead. + placeholder: | + Tapping a track in an album plays the whole library instead of the album. + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: Numbered steps someone else can follow on a fresh install. + placeholder: | + 1. Copy 3 albums to the device's Music folder + 2. Open the Albums tab, tap the second album + 3. Tap the third track + 4. Open the full-screen player and skip forward + validations: + required: true + + - type: input + id: android-version + attributes: + label: Android version + placeholder: "Android 15 (API 35)" + validations: + required: true + + - type: input + id: device + attributes: + label: Device + description: Model, or the emulator you used. + placeholder: "Pixel 8 — or Pixel 8 API 35 emulator" + validations: + required: true + + - type: input + id: version + attributes: + label: WaveFlow version or commit + placeholder: "main @ a1b2c3d" + validations: + required: true + + - type: textarea + id: files + attributes: + label: The files involved + description: >- + For anything touching the library, playback, or artwork, this is + usually the decisive detail. Container and codec (m4a/AAC, mp3, FLAC…), + and which tags are present — an album splitting apart almost always + means a missing `albumArtist`. `mediainfo` or a desktop tag editor will + tell you. + placeholder: | + 7 × m4a/AAC ripped from Apple Music. Tags: title, artist, album, artwork. + No albumArtist tag. + + - type: textarea + id: extra + attributes: + label: Screenshots, screen recordings, or logs + description: >- + Drag files in directly. A `logcat` capture around the moment of the bug + helps a lot for crashes (`adb logcat` filtered on `app.waveflow`). diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..a6ee2fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: false +contact_links: + - name: Security disclosure + url: https://github.com/InstaZDLL/waveflow-android/blob/main/.github/SECURITY.md + about: Report a vulnerability privately — please do not open a public issue. + - name: Question or setup help + url: https://github.com/InstaZDLL/WaveFlow/discussions/categories/q-a + about: "Ask in the main WaveFlow Q&A — 'how do I…', 'is this a bug or by design?'" + - name: Feature idea or UX proposal + url: https://github.com/InstaZDLL/WaveFlow/discussions/categories/ideas + about: Discuss the idea first; concrete feature requests can graduate to an issue afterward. + - name: Desktop or iOS issue + url: https://github.com/InstaZDLL/WaveFlow + about: This repository is the Android client only. Desktop and iOS live elsewhere. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..a95ec91 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,54 @@ +name: Feature request +description: Propose a concrete change to WaveFlow for Android. +labels: ["type: feat", "needs triage"] +body: + - type: markdown + attributes: + value: | + If the idea is still taking shape, start a + [discussion](https://github.com/InstaZDLL/WaveFlow/discussions/categories/ideas) + instead — it can graduate to an issue once it's concrete. + + Check the roadmap in the README first: playlists, search, and server + sync are already planned and don't need a new issue. + + - type: textarea + id: problem + attributes: + label: The problem + description: What can't you do today? Describe the situation, not the solution. + placeholder: | + With ~2000 tracks, scrolling the Titres tab to reach anything past "M" + takes forever. + validations: + required: true + + - type: textarea + id: proposal + attributes: + label: What you'd like instead + description: Be specific about the behaviour, not just the feature name. + validations: + required: true + + - type: dropdown + id: parity + attributes: + label: Does this exist in another WaveFlow client? + description: >- + The three clients are meant to stay coherent. If desktop or iOS + already does it, matching their behaviour is usually the answer. + options: + - "No — Android-specific" + - "Yes, on desktop" + - "Yes, on iOS" + - "Yes, on both" + - "Not sure" + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives you considered + description: Including "do nothing" — say why it isn't enough. diff --git a/.github/SECURITY.md b/.github/SECURITY.md new file mode 100644 index 0000000..19c05c7 --- /dev/null +++ b/.github/SECURITY.md @@ -0,0 +1,58 @@ +# Security Policy + +Thank you for reporting security vulnerabilities responsibly before any public +disclosure. + +## Supported Versions + +WaveFlow for Android does not have long-term version support yet. The main branch +and the latest published release should be considered the only supported +versions for security fixes. + +| Version | Supported | +| ------------------------------------------------- | --------- | +| `main` / latest published release | Yes | +| Older versions, snapshots, and unmaintained forks | No | + +## Reporting a Vulnerability + +**Do not open a public issue for security vulnerabilities.** + +Use one of these channels, depending on what is available on the public +repository: + +1. **GitHub Security Advisories**: open the repository's _Security_ tab, then + choose _Report a vulnerability_. This is the recommended confidential + channel. +2. Contact the maintainers privately if GitHub Security Advisories are not + available. + +Your report should include: + +- the affected version (or commit) and the Android version you ran it on; +- a description of the vulnerability and its impact; +- reproduction steps, and a sample file if the issue is triggered by one; +- any suggested fix, if you have one. + +Please allow a reasonable delay for a fix before public disclosure. + +## Scope + +Things that are in scope for this repository: + +- reading and parsing audio files surfaced through `MediaStore` — malformed or + hostile tags, artwork, and container structures; +- anything that could let a file or intent escape the app's scoped storage or + read/overwrite data outside the app's own storage; +- exported components (activities, services, receivers, providers) and the + intents they accept; +- the future WaveFlow server sync (signed URLs, credential handling) once it + lands. + +Out of scope: + +- vulnerabilities in Android itself or in vendor OS builds (report those to the + respective vendor); +- issues that require a rooted device, a hostile ADB session, or physical access + to an unlocked phone; +- the desktop and iOS clients — report those on their own repositories. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..0e3d091 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,38 @@ +version: 2 + +updates: + - package-ecosystem: gradle + directory: "/" + schedule: + interval: weekly + day: monday + time: "06:15" + timezone: Europe/Zurich + open-pull-requests-limit: 10 + labels: + - dependencies + - gradle + commit-message: + prefix: chore + groups: + gradle-all: + patterns: + - "*" + + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly + day: monday + time: "06:15" + timezone: Europe/Zurich + open-pull-requests-limit: 10 + labels: + - dependencies + - github-actions + commit-message: + prefix: chore + groups: + github-actions-all: + patterns: + - "*" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..89507bd --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,50 @@ +# Étiquettes basées sur les chemins, pour actions/labeler. +# Les scopes reflètent le découpage du package app.waveflow. + +"scope: model": + - changed-files: + - any-glob-to-any-file: + - "app/src/main/java/app/waveflow/model/**" + +"scope: data": + - changed-files: + - any-glob-to-any-file: + - "app/src/main/java/app/waveflow/data/**" + +"scope: playback": + - changed-files: + - any-glob-to-any-file: + - "app/src/main/java/app/waveflow/playback/**" + +"scope: ui": + - changed-files: + - any-glob-to-any-file: + - "app/src/main/java/app/waveflow/ui/**" + - "app/src/main/res/**" + +"scope: project": + - changed-files: + - any-glob-to-any-file: + - "**/*.gradle.kts" + - "gradle/**" + - "gradle.properties" + - "settings.gradle.kts" + - "app/src/main/AndroidManifest.xml" + +"scope: tests": + - changed-files: + - any-glob-to-any-file: + - "app/src/test/**" + - "app/src/androidTest/**" + +"scope: ci": + - changed-files: + - any-glob-to-any-file: + - ".github/workflows/**" + - ".github/dependabot.yml" + - ".github/labeler.yml" + +"scope: docs": + - changed-files: + - any-glob-to-any-file: + - "**/*.md" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..88b365a --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,52 @@ + + +## Summary + + + +- +- + +## How I tested + + + +- +- + +## Screenshots / clips + + + +## Checklist + +- [ ] Title uses Conventional Commits (`type(scope): subject`, kebab-case scope) +- [ ] Builds and unit tests pass locally (`./gradlew testDebugUnitTest`) +- [ ] UI changes checked in light *and* dark theme +- [ ] Playback changes checked from the notification / lock-screen controls +- [ ] Breaking change? Called out in the summary above + +## Linked issues + + + +Closes # diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml new file mode 100644 index 0000000..a83d633 --- /dev/null +++ b/.github/workflows/label-pr.yml @@ -0,0 +1,110 @@ +name: Label PR + +on: + pull_request: + types: [opened, synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + label: + runs-on: ubuntu-latest + timeout-minutes: 5 + + # Prefer the maintainer-provided PAT (`LABELER_PAT`) when set, fall back to + # the workflow's auto-generated `GITHUB_TOKEN` otherwise — same setup as + # the desktop repo, where the auto token started returning spurious 401s + # on POST /labels. Empty secrets are falsy in this ternary, so unset → + # fallback works without extra plumbing. + env: + LABEL_TOKEN: ${{ secrets.LABELER_PAT || secrets.GITHUB_TOKEN }} + + steps: + # Scope labels based on changed files + - name: Path-based labels + uses: actions/labeler@bf12e9b00b37c5c0ca2b87b79b2daf7891dbda13 # v7.0.0 + with: + repo-token: ${{ env.LABEL_TOKEN }} + sync-labels: true + + # Type labels based on PR title (conventional commits). + # `context.payload.pull_request.title` stays inside the github-script JS + # context — never interpolated into a shell — so there is no injection + # risk here. + - name: Type labels + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + github-token: ${{ env.LABEL_TOKEN }} + script: | + const title = context.payload.pull_request.title; + const prefixMap = { + 'feat': 'type: feat', + 'fix': 'type: fix', + 'chore': 'type: chore', + 'docs': 'type: docs', + 'refactor': 'type: refactor', + 'perf': 'type: perf', + 'test': 'type: test', + 'ci': 'type: ci', + }; + + const match = title.match(/^(\w+)(\(.+\))?[!]?:/); + const prefix = match?.[1]; + const label = prefixMap[prefix]; + + if (label) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: [label], + }); + } + + # Size labels based on diff + - name: Size labels + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + github-token: ${{ env.LABEL_TOKEN }} + script: | + const { data: files } = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + per_page: 100, + }); + + const lines = files.reduce((sum, f) => sum + f.additions + f.deletions, 0); + const sizeLabels = [ + { max: 10, label: 'size: xs' }, + { max: 50, label: 'size: s' }, + { max: 200, label: 'size: m' }, + { max: 500, label: 'size: l' }, + ]; + const sizeLabel = sizeLabels.find(s => lines <= s.max)?.label || 'size: xl'; + + // Remove old size labels + const current = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + for (const l of current.data.filter(l => l.name.startsWith('size:'))) { + if (l.name !== sizeLabel) { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: l.name, + }); + } + } + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: [sizeLabel], + }); diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..a4694a1 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,83 @@ +# Contributor Covenant 3.0 Code of Conduct + +## Our Pledge + +We pledge to make our community welcoming, safe, and equitable for all. + +We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant. + +## Encouraged Behaviors + +While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language. + +With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including: + +1. Respecting the **purpose of our community**, our activities, and our ways of gathering. +2. Engaging **kindly and honestly** with others. +3. Respecting **different viewpoints** and experiences. +4. **Taking responsibility** for our actions and contributions. +5. Gracefully giving and accepting **constructive feedback**. +6. Committing to **repairing harm** when it occurs. +7. Behaving in other ways that promote and sustain the **well-being of our community**. + +## Restricted Behaviors + +We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct. + +1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop. +2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people. +3. **Stereotyping or discrimination.** Characterizing anyone's personality or behavior on the basis of immutable identities or traits. +4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community. +5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission. +6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group. +7. Behaving in other ways that **threaten the well-being** of our community. + +### Other Restrictions + +1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions. +2. **Failing to credit sources.** Not properly crediting the sources of content you contribute. +3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community. +4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors. + +## Reporting an Issue + +Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm. + +When an incident does occur, it is important to report it promptly. To report a possible violation, contact the project maintainer at **github.105mh@8shield.net** — or, for issues that may involve the maintainer themselves, open a private security advisory at . Reports will be acknowledged within 48 hours, and all communications will be kept confidential. + +Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution. + +## Addressing and Repairing Harm + +If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped. + +1. Warning + 1. Event: A violation involving a single incident or series of incidents. + 2. Consequence: A private, written warning from the Community Moderators. + 3. Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations. +2. Temporarily Limited Activities + 1. Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation. + 2. Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members. + 3. Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over. +3. Temporary Suspension + 1. Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation. + 2. Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions. + 3. Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted. +4. Permanent Ban + 1. Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member. + 2. Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior. + 3. Repair: There is no possible repair in cases of this severity. + +This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/). + +Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/) + +For answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla's code of conduct team](https://github.com/mozilla/inclusion). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3535b2e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,58 @@ +# Contributing to WaveFlow for Android + +Thanks for helping on the Android client. The main +[WaveFlow CONTRIBUTING guide](https://github.com/InstaZDLL/WaveFlow/blob/main/CONTRIBUTING.md) +(commit conventions, PR process, the family's shared expectations) applies here +too — this file only adds the Android-specific bits. + +By participating you agree to the [Code of Conduct](CODE_OF_CONDUCT.md). + +## Getting set up + +Open the project in Android Studio, or build from the command line with the +Gradle wrapper (JDK 21 — the CI and the version catalog target it): + +```bash +./gradlew assembleDebug +``` + +The app is Kotlin + Jetpack Compose + Media3, with dependencies pinned in the +`gradle/libs.versions.toml` version catalog. + +## Before you open a PR + +```bash +./gradlew testDebugUnitTest # unit tests +./gradlew lintDebug # Android lint +``` + +Check UI changes in **both light and dark** theme — the player tints itself from +the artwork — and verify playback changes from the notification and lock-screen +media controls. + +## Commit conventions + +[Conventional Commits](https://www.conventionalcommits.org/) with **kebab-case** +scopes and a **lowercase** subject, same as the rest of the family. Scopes mirror +the areas in [`.github/labeler.yml`](.github/labeler.yml): + +- `feat(ui): drag-to-reorder in the queue` +- `fix(playback): keep the album context when tapping a track` +- `refactor(data): fold artwork extraction into the scanner` + +## Staying coherent with the other clients + +The desktop, iOS, and Android clients are meant to stay coherent. When you add a +user-facing behavior, check whether desktop or iOS already does it and match that +behavior rather than inventing a new one. + +## Reporting bugs and security issues + +- Bugs and feature requests: use the [issue templates](.github/ISSUE_TEMPLATE/). +- Security vulnerabilities: **do not** open a public issue — follow + [SECURITY.md](.github/SECURITY.md). + +## License + +WaveFlow for Android is **GPL-3.0-only**. By submitting a pull request you agree +that your contribution is licensed under those terms.