Skip to content

Latest commit

 

History

History
89 lines (63 loc) · 3.75 KB

File metadata and controls

89 lines (63 loc) · 3.75 KB

Contributing

This is a hobby project I work on to learn Kotlin, so it moves at a hobby pace and I sometimes pick the more educational option over the most efficient one. PRs and issues are welcome anyway.

Filing an issue

Issues live on Codeberg. Use one of these prefixes in the title so the tracker stays readable:

  • feat: something a player would notice
  • fix: a bug
  • chore: tooling, refactor, deps, CI
  • docs: README, inline docs, comments

If it makes sense, add an area label: area/app, area/core, area/server, area/ci.

Sending a PR

Fork on Codeberg, branch off main, keep the PR small. One feature or one fix per PR.

Commit messages use the same prefixes as issue titles. Short subject (around 72 chars), body optional.

Before I'll merge:

  • ./gradlew :app:lint is clean
  • ktlint is clean
  • Tests for any pure-Kotlin code you added pass
  • For UI changes, include a screenshot in the PR description. Light and dark mode if the change is visible.

Code style

Kotlin official style, ktlint enforces it.

  • Prefer val and pure functions, especially in domain code.
  • Anything in domain/ should be plain Kotlin, no Android or Compose imports. It needs to be JVM-testable and reusable by the server.
  • Avoid !!. If you really need it, leave a one-line comment saying why.
  • Keep Composables small. Hoist state to ViewModels.

Releasing

CI is Woodpecker on Codeberg (.woodpecker/). Every push and PR runs lint and unit tests. Pushing a v* tag builds a signed APK and AAB and attaches the APK to the matching Codeberg release.

Signing is driven by environment variables, never a committed keystore:

  • NONONO_KEYSTORE - path to the .jks
  • NONONO_KEYSTORE_PASSWORD, NONONO_KEY_ALIAS, NONONO_KEY_PASSWORD

Without them the release variant still builds, just unsigned (what F-Droid expects). For CI these are Woodpecker secrets; the keystore is passed as a base64 secret and decoded at build time. Keystores and keystore.properties are gitignored.

To cut a release: bump versionCode/versionName in app/build.gradle.kts, add a CHANGELOG.md entry and a fastlane/metadata/android/en-US/changelogs/<versionCode>.txt, then tag vX.Y.Z and push the tag. F-Droid picks up the tag and the fastlane metadata; the Play listing is updated from the same metadata; the Codeberg release is created by CI.

Adding a picture

Pictures are PNG files in app/src/main/assets/pictures/, named <id>__<DisplayName>__<size>.png:

  • id: lowercase [a-z0-9-], unique. DisplayName: _ renders as a space.
  • size: exactly 5, 10 or 15, and the PNG must be exactly that many pixels wide and tall.
  • Filled rule: a pixel is a filled cell iff it is opaque (alpha >= 128) AND dark (luma < 0.5, luma = 0.299R + 0.587G + 0.114B over 255). Light or transparent pixels are empty.
  • Constraints: no fully-empty row or column, and the puzzle must be uniquely solvable as drawn. There is no auto-fixing; PictureAssetsTest (run by CI via ./gradlew :app:testDebugUnitTest) fails and prints every offending filename so you can tweak pixels.

To bulk-import a silhouette pack instead of drawing by hand, see tools/pixel-import/README.md (vendor solid silhouettes, run the guarded importer; the same gate culls anything not uniquely solvable). Detailed multi-colour sprites do not work: they binarise into noise.

Licensing: this project is GPL-3.0-or-later. Bundled art must be CC0 / public domain, or GPL-compatible (incl. CC-BY 3.0/4.0). Non-CC0 art needs a row in app/src/main/assets/pictures_credits.tsv and an entry in CREDITS.md; it then shows in Settings -> Attributions. Do not commit copyrighted or AI-laundered third-party art.

Conduct

Be kind, assume good faith, disagree about technical direction all you want, leave the personal stuff out.