Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 63 additions & 4 deletions .github/AI_STYLE_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,29 @@

This project is a media server client for Android, supporting both Plex and Emby servers. It's built with a focus on a clean, maintainable architecture, leveraging modern Android development practices.

## General Principles

* Restrict actions to only the relevant tasks, do not go outside the guidelines.
* If you do see a problem mention it and ask before attempting to fix it.
* Describe how you would like to fix it before proceeding.
* Proceed only after permission is granted.
* Always try to do work that optimizes your token usage but not exceeds it.

## GIT interactions

- Delete unused or obsolete files when your changes make them irrelevant (refactors, feature removals, etc.), and revert files only when the change is yours or explicitly requested. If a git operation leaves you unsure about other agents' in-flight work, stop and coordinate instead of deleting.
- **Before attempting to delete a file to resolve a local type/lint failure, stop and ask the user.** Other agents are often editing adjacent files; deleting their work to silence an error is never acceptable without explicit approval.
- NEVER edit `.env` or any environment variable files—only the user may change them.
- Coordinate with other agents before removing their in-progress edits—don't revert or delete work you didn't author unless everyone agrees.
- Moving/renaming and restoring files is allowed.
- ABSOLUTELY NEVER run destructive git operations (e.g., `git reset --hard`, `rm`, `git checkout`/`git restore` to an older commit) unless the user gives an explicit, written instruction in this conversation. Treat these commands as catastrophic; if you are even slightly unsure, stop and ask before touching them. *(When working within Cursor or Codex Web, these git limitations do not apply; use the tooling's capabilities as needed.)*
- Never use `git restore` (or similar commands) to revert files you didn't author—coordinate with other agents instead so their in-progress work stays intact.
- Always double-check git status before any commit
- Keep commits atomic: commit only the files you touched and list each path explicitly. For tracked files run `git commit -m "<scoped message>" -- path/to/file1 path/to/file2`. For brand-new files, use the one-liner `git restore --staged :/ && git add "path/to/file1" "path/to/file2" && git commit -m "<scoped message>" -- path/to/file1 path/to/file2`.
- Quote any git paths containing brackets or parentheses (e.g., `src/app/[candidate]/**`) when staging or committing so the shell does not treat them as globs or subshells.
- When running `git rebase`, avoid opening editors—export `GIT_EDITOR=:` and `GIT_SEQUENCE_EDITOR=:` (or pass `--no-edit`) so the default messages are used automatically.
- Never amend commits unless you have explicit written approval in the task thread.

## Core Frameworks

* **MVP (Model-View-Presenter):** The application follows the MVP architectural pattern, using the **Moxy** framework to facilitate this. Presenters are responsible for business logic, while views (Activities and Fragments) are responsible for displaying data and handling user input.
Expand All @@ -26,11 +49,47 @@ This project is a media server client for Android, supporting both Plex and Emby
* **Testing:**
* Write unit tests for all new features and bug fixes.
* Use MockK for mocking dependencies in unit tests.
* **Instantiation:** Mocks should be defined as properties within the test class, instantiated directly with the `mockk()` function. The use of `relaxed = true` is preferred to avoid boilerplate stubbing. Do **not** use the `@MockK` annotation or `MockKRule`.

*Correct Example (`MainActivityTest.kt`):*
'''kotlin
private val mockSharedPreferences: SharedPreferences = mockk(relaxed = true)
private val mockPresenter: MainPresenter = mockk(relaxed = true)
'''

* **Lifecycle Management:** Use standard JUnit `@Before` for setup and `@After` for teardown. The `@After` method must call `clearAllMocks()` to ensure tests do not interfere with each other.

*Correct Example (`MainActivityTest.kt`):*
'''kotlin
@Before
fun setUp() {
// Stub mock behavior
every { mockSharedPreferences.getBoolean("serenity_first_run", true) } returns true
}

@After
fun tearDown() {
activity.finish()
clearAllMocks()
Toothpick.reset()
}
'''
Comment on lines +52 to +76
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix code block delimiters and list indentation in MockK guidance. The code examples use triple quotes (''') instead of standard markdown backticks (```). Additionally, the nested list structure violates markdown list indentation rules (MD007). The outer bullet for Instantiation and Lifecycle Management should be indented by 4 spaces from the parent, and nested sub-bullets should follow a consistent 4-space indent pattern.

Apply this diff to fix formatting:

-    *   **Instantiation:** Mocks should be defined as properties within the test class, instantiated directly with the `mockk()` function. The use of `relaxed = true` is preferred to avoid boilerplate stubbing. Do **not** use the `@MockK` annotation or `MockKRule`.
-        
-        *Correct Example (`MainActivityTest.kt`):*
-        
-        '''kotlin
-        private val mockSharedPreferences: SharedPreferences = mockk(relaxed = true)
-        private val mockPresenter: MainPresenter = mockk(relaxed = true)
-        '''
+    - **Instantiation:** Mocks should be defined as properties within the test class, instantiated directly with the `mockk()` function. The use of `relaxed = true` is preferred to avoid boilerplate stubbing. Do **not** use the `@MockK` annotation or `MockKRule`.
+
+      *Correct Example (`MainActivityTest.kt`):*
+      ```kotlin
+      private val mockSharedPreferences: SharedPreferences = mockk(relaxed = true)
+      private val mockPresenter: MainPresenter = mockk(relaxed = true)
+      ```
-
-        *   **Lifecycle Management:** Use standard JUnit `@Before` for setup and `@After` for teardown. The `@After` method must call `clearAllMocks()` to ensure tests do not interfere with each other.
-
-            *Correct Example (`MainActivityTest.kt`):*
-            '''kotlin
-            @Before
-            fun setUp() {
-              // Stub mock behavior
-              every { mockSharedPreferences.getBoolean("serenity_first_run", true) } returns true
-            }
-
-            @After
-            fun tearDown() {
-              activity.finish()
-              clearAllMocks()
-              Toothpick.reset()
-            }
-            '''
+    - **Lifecycle Management:** Use standard JUnit `@Before` for setup and `@After` for teardown. The `@After` method must call `clearAllMocks()` to ensure tests do not interfere with each other.
+
+      *Correct Example (`MainActivityTest.kt`):*
+      ```kotlin
+      @Before
+      fun setUp() {
+        // Stub mock behavior
+        every { mockSharedPreferences.getBoolean("serenity_first_run", true) } returns true
+      }
+
+      @After
+      fun tearDown() {
+        activity.finish()
+        clearAllMocks()
+        Toothpick.reset()
+      }
+      ```
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

52-52: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


60-60: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)

🤖 Prompt for AI Agents
.github/AI_STYLE_GUIDE.md lines 52-76: code fences and list indentation in the
MockK guidance are malformed (triple single-quotes used and list levels
mis-indented); replace the '''kotlin fences with proper triple backticks
(```kotlin) around both code examples, ensure the Instantiation and Lifecycle
Management bullets are indented consistently as nested list items (use four
spaces from the parent bullet), remove stray stray diff markers/extra hyphens,
and apply the provided replacement so the Instantiation example ends with a
closing ``` and the Lifecycle Management section is a properly indented nested
bullet with its own ```kotlin fenced example.


* **Static Mocks:** For mocking objects, companion objects, or constructors (e.g., `mockkStatic`, `mockkObject`), mocking and unmocking should be handled within `@BeforeClass` and `@AfterClass` methods in a `companion object`. Call `unmockAll()` in the `@AfterClass` method.
* Use Robolectric to test Android framework-dependent code.
* **Naming Conventions:**
* Follow the standard Kotlin naming conventions.
* Name presenters with the `Presenter` suffix (e.g., `MainPresenter`).
* Name views with the `View` suffix (e.g., `MainView`).
* When converting tests from Java to Kotlin, replace AssertJ assertions with their AssertK equivalents.
* Toothpick Rules for Tests:
* * **Inherit from `InjectingTest`**: All test classes that require dependency injection must extend the `us.nineworlds.us.nineworlds.serenity.test.InjectingTest` base class.
* **Override `setUp` and Call `super.setUp()` First**: It's critical to override the `@Before setUp()` method. The very first line must be `super.setUp()`. This ensures the scope is opened and your test modules are installed before the component under test (e.g., an Activity) is created.
* **Implement `installTestModules()`**: You must implement the abstract `installTestModules()` method. This is where you will install your test-specific dependency configurations.
* **Define Bindings in an Inner `Module` Class**: Create an inner class that extends `Module` within your test class. This encapsulates all the specific bindings for that test, keeping it self-contained and easy to understand.
* **Manually Bind Mock Instances**: Inside your inner `Module`, manually bind each mock object to its corresponding class or interface using `bind(SomeClass::class.java).toInstance(mockInstance)`.
* **Use `scope.installTestModules()` for Installation**: Within the `installTestModules()` override, use `scope.installTestModules()` to add one or more of your configured test modules. You can add both shared test modules and the specific inner class module you created.
* **Trust the Base Class for Cleanup**: The `InjectingTest` base class automatically handles resetting Toothpick. You can add an `@After` method for other cleanup tasks, like clearing mocks.
Comment on lines +78 to +88
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix Toothpick Rules subsection list indentation and syntax. The nested list items are severely misaligned, and line 82 contains a syntax error (extra asterisk: * * ). The section should use consistent 4-space indentation for sub-bullets. Apply this diff:

-    *   **Static Mocks:** For mocking objects, companion objects, or constructors (e.g., `mockkStatic`, `mockkObject`), mocking and unmocking should be handled within `@BeforeClass` and `@AfterClass` methods in a `companion object`. Call `unmockAll()` in the `@AfterClass` method.
+    - **Static Mocks:** For mocking objects, companion objects, or constructors (e.g., `mockkStatic`, `mockkObject`), mocking and unmocking should be handled within `@BeforeClass` and `@AfterClass` methods in a `companion object`. Call `unmockAll()` in the `@AfterClass` method.
     *   Use Robolectric to test Android framework-dependent code.
-    *   When converting tests from Java to Kotlin, replace AssertJ assertions with their AssertK equivalents.
-    * Toothpick Rules for Tests:
-
-        * *   **Inherit from `InjectingTest`**: All test classes that require dependency injection must extend the `us.nineworlds.us.nineworlds.serenity.test.InjectingTest` base class.
-
-        *   **Override `setUp` and Call `super.setUp()` First**: It's critical to override the `@Before setUp()` method. The very first line must be `super.setUp()`. This ensures the scope is opened and your test modules are installed before the component under test (e.g., an Activity) is created.
-
-        *   **Implement `installTestModules()`**: You must implement the abstract `installTestModules()` method. This is where you will install your test-specific dependency configurations.
-
-        *   **Define Bindings in an Inner `Module` Class**: Create an inner class that extends `Module` within your test class. This encapsulates all the specific bindings for that test, keeping it self-contained and easy to understand.
-
-        *   **Manually Bind Mock Instances**: Inside your inner `Module`, manually bind each mock object to its corresponding class or interface using `bind(SomeClass::class.java).toInstance(mockInstance)`.
-
-        *   **Use `scope.installTestModules()` for Installation**: Within the `installTestModules()` override, use `scope.installTestModules()` to add one or more of your configured test modules. You can add both shared test modules and the specific inner class module you created.
-
-        *   **Trust the Base Class for Cleanup**: The `InjectingTest` base class automatically handles resetting Toothpick. You can add an `@After` method for other cleanup tasks, like clearing mocks.
+    - **When converting tests from Java to Kotlin**, replace AssertJ assertions with their AssertK equivalents.
+    - **Toothpick Rules for Tests:**
+        - **Inherit from `InjectingTest`**: All test classes that require dependency injection must extend the `us.nineworlds.us.nineworlds.serenity.test.InjectingTest` base class.
+        - **Override `setUp` and Call `super.setUp()` First**: It's critical to override the `@Before setUp()` method. The very first line must be `super.setUp()`. This ensures the scope is opened and your test modules are installed before the component under test (e.g., an Activity) is created.
+        - **Implement `installTestModules()`**: You must implement the abstract `installTestModules()` method. This is where you will install your test-specific dependency configurations.
+        - **Define Bindings in an Inner `Module` Class**: Create an inner class that extends `Module` within your test class. This encapsulates all the specific bindings for that test, keeping it self-contained and easy to understand.
+        - **Manually Bind Mock Instances**: Inside your inner `Module`, manually bind each mock object to its corresponding class or interface using `bind(SomeClass::class.java).toInstance(mockInstance)`.
+        - **Use `scope.installTestModules()` for Installation**: Within the `installTestModules()` override, use `scope.installTestModules()` to add one or more of your configured test modules. You can add both shared test modules and the specific inner class module you created.
+        - **Trust the Base Class for Cleanup**: The `InjectingTest` base class automatically handles resetting Toothpick. You can add an `@After` method for other cleanup tasks, like clearing mocks.

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

78-78: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


79-79: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


80-80: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


81-81: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


82-82: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


82-82: Unordered list indentation
Expected: 6; Actual: 10

(MD007, ul-indent)


83-83: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


84-84: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


85-85: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


86-86: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


87-87: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)


88-88: Unordered list indentation
Expected: 4; Actual: 8

(MD007, ul-indent)

🤖 Prompt for AI Agents
In .github/AI_STYLE_GUIDE.md around lines 78 to 88, the "Toothpick Rules for
Tests" subsection has misaligned nested list items and a stray extra asterisk on
line 82; fix it by normalizing the nested list to use consistent 4-space
indentation for each sub-bullet, remove the redundant `*` on line 82, and ensure
all bullet markers and inline formatting (e.g., bold markers) are consistent and
syntactically correct so the list renders properly.

* **Naming Conventions:**
* Follow the standard Kotlin naming conventions.
* Name presenters with the `Presenter` suffix (e.g., `MainPresenter`).
* Name views with the `View` suffix (e.g., `MainView`).

---

Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading