Project Conventions (Nextcloud Notes)
Apply these to every file you write so the change passes review.
SPDX Header (every new/renamed file)
The IDE keeps the old license block. Replace it with the current template. The year is the
year the Kotlin file is created. New contributions are AGPL-3.0-or-later; keep
OR GPL-2.0-only only if the original file carried it.
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: <YEAR> Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
If the developer wants personal attribution, the form
SPDX-FileCopyrightText: <YEAR> <Name> <email> is also used — match what the developer
asks for; default to the "Nextcloud GmbH and Nextcloud contributors" line.
Structural Rules
- ≤300 lines per file, and a file already at or above 300 lines must not grow. If
decomposition pushes past it, split responsibilities into separate files/collaborators and
tell the developer. Do not reach for
@Suppress("LargeClass", "TooManyFunctions")— those are detekt rule names and this repository has no detekt, so the annotation suppresses nothing and merely hides the problem from the reader. - ≤120 columns per line.
- One top-level type per file. Extract models, states, sealed classes, and listener interfaces into their own files rather than nesting many types in one.
- Exactly one trailing newline at end of file.
No Magic Numbers / Hardcoded Resources
- Extract literals into named
const valin acompanion object(MIN_SHOW_ALL_VISIBLE_ITEM_COUNT = 3,INTERNAL_LINK_PATH_PRETTY = "/f/"). - Strings, colors, dimens come from resources (
R.string.*,R.dimen.*), never inline. - Only
app/src/main/res/values/strings.xmlmay be edited for strings; never touchvalues-*translation folders.
Comments & Naming
- No decorative divider comments (
// ==== ====,// ---- Title ----).// region/// endregionfor IDE folding is allowed and should match the file's existing style. - Prefer self-explanatory names over per-function KDoc. Preserve genuinely informative Javadoc as KDoc (invariant 4); drop noise.
- Do not use multiple boolean flags to model state — use an
enum/sealed class.
Modern Java Interop
When the file still has Java callers, keep the Java-facing API clean:
@JvmStatic for factory/companion functions, @JvmField for exposed constants,
@JvmOverloads for defaulted params, @Throws for checked exceptions.
Git & Commits (developer-driven)
- Preserve history: the rename
git mv Foo.java Foo.ktshould be a separate commit from the content change sogit blamefollows through. - Conventional Commits (
refactor(sharing): convert FileDetailSharingFragment to Kotlin). - Every AI-assisted commit needs an
Assisted-by: <agent>:<model>trailer. - Only the human contributor adds
Signed-off-by(DCO). You must never add it, and never open PRs/issues autonomously (AI policy).
Quality Gate
These are the tasks this project actually has. gplay is not a flavor here — the flavors
are fdroid, play, dev, and qa.
./gradlew lintFdroidDebug
./gradlew testFdroidDebugUnitTest
./gradlew createFdroidDebugUnitTestCoverageReport # JaCoCo, debug builds only
./gradlew check # lint + unit tests for all variants
Fix every finding in the files you changed before declaring done. Style rules that no task enforces — line length, trailing newline, import order — are on you to check by reading the diff.