From 2383359aced142cf913ef7f68c847175c4a12845 Mon Sep 17 00:00:00 2001 From: sameerasw Date: Wed, 19 Aug 2026 09:13:24 +0530 Subject: [PATCH 1/3] docs: add Quick Settings tile implementation guide --- docs/ADD_QS_TILE.md | 204 +++++++++++++++++++++++++++++++ docs/SERVICES_AND_PERMISSIONS.md | 7 ++ 2 files changed, 211 insertions(+) create mode 100644 docs/ADD_QS_TILE.md diff --git a/docs/ADD_QS_TILE.md b/docs/ADD_QS_TILE.md new file mode 100644 index 000000000..6ef143d1b --- /dev/null +++ b/docs/ADD_QS_TILE.md @@ -0,0 +1,204 @@ +# Quick Settings (QS) Tile Implementation Guide + +This guide details the end-to-end process of implementing, registering, and maintaining Quick Settings (QS) tiles within the **Essentials** architecture. + +For system architecture context, refer to [ARCHITECTURE.md](file:///Users/sameerasandakelum/GIT/essentials/docs/ARCHITECTURE.md), [STRUCTURE.md](file:///Users/sameerasandakelum/GIT/essentials/docs/STRUCTURE.md), and [SERVICES_AND_PERMISSIONS.md](file:///Users/sameerasandakelum/GIT/essentials/docs/SERVICES_AND_PERMISSIONS.md). + +--- + +## Architectural Overview + +Quick Settings tile integration operates across three core layers: + +``` +┌─────────────────────────────────────────────────────────────┐ +│ System & Shade │ +│ Android Quick Settings Shade (SystemUI) │ +└──────────────────────────────┬──────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────┐ +│ BaseTileService Layer │ +│ - Standardized lifecycle & background coroutine scope │ +│ - Secure / Global settings cache & fallback bridge │ +│ - Permission & device support validation │ +│ - Built-in haptic feedback │ +└──────────────────────────────┬──────────────────────────────┘ + │ + ┌─────────────────────┴─────────────────────┐ + ▼ ▼ +┌─────────────────────────────────┐ ┌──────────────────────────────┐ +│ Discovery & Headless Execution │ │ In-App Tile Manager UI │ +│ - QsTileRegistry │ │ - QuickSettingsTilesSettingsUI +│ - QsTileActionRouter │ │ - StatusBarManager tile add │ +│ - QsTilesWidget (Glance) │ │ - PermissionsBottomSheet │ +└─────────────────────────────────┘ └──────────────────────────────┘ +``` + +--- + +## Step-by-Step Implementation Workflow + +### 1. Create Tile Service Class + +All QS tile services are located in `app/src/main/java/com/sameerasw/essentials/services/tiles/` and must extend [`BaseTileService`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/java/com/sameerasw/essentials/services/tiles/BaseTileService.kt). + +#### Implementation Example: + +```kotlin +package com.sameerasw.essentials.services.tiles + +import android.Manifest +import android.content.pm.PackageManager +import android.graphics.drawable.Icon +import android.service.quicksettings.Tile +import com.sameerasw.essentials.R +import com.sameerasw.essentials.utils.DeviceUtils + +class FeatureTileService : BaseTileService() { + + override fun getTileLabel(): String = getString(R.string.tile_feature_label) + + override fun getTileSubtitle(): String { + return if (isFeatureActive()) getString(R.string.on) else getString(R.string.off) + } + + override fun hasFeaturePermission(): Boolean { + return checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) == PackageManager.PERMISSION_GRANTED + } + + override fun isDeviceSupported(): Boolean { + // Optional override: Return false if feature is restricted to specific hardware/OEMs + return true + } + + override fun getTileIcon(): Icon? { + val iconRes = if (isFeatureActive()) { + R.drawable.rounded_feature_active_24 + } else { + R.drawable.rounded_feature_inactive_24 + } + return Icon.createWithResource(this, iconRes) + } + + override fun getTileState(): Int { + return if (isFeatureActive()) Tile.STATE_ACTIVE else Tile.STATE_INACTIVE + } + + override fun onTileClick() { + // Asynchronous execution within service coroutine scope + val newState = if (isFeatureActive()) 0 else 1 + putSecureInt("secure_feature_setting_key", newState) + } + + private fun isFeatureActive(): Boolean { + return getSecureInt("secure_feature_setting_key", 0) == 1 + } +} +``` + +#### `BaseTileService` Methods Reference: + +| Method | Return Type | Description | +| :--- | :--- | :--- | +| `onTileClick()` | `Unit` | Executed asynchronously when the tile is tapped. | +| `getTileLabel()` | `String` | Primary title string rendered on the tile. | +| `getTileSubtitle()` | `String` | Secondary status text (e.g. "On", "Off", timer remaining). | +| `getTileState()` | `Int` | `Tile.STATE_ACTIVE` or `Tile.STATE_INACTIVE`. | +| `hasFeaturePermission()` | `Boolean` | Permission validation. Returns `Tile.STATE_UNAVAILABLE` when `false`. | +| `isDeviceSupported()` | `Boolean` | Compatibility check. Controlled by "Enable unsupported features" setting. | +| `getTileIcon()` | `Icon?` | Optional dynamic icon resolution based on feature state. | +| `getSecureInt()` / `putSecureInt()` | `Int` / `Unit` | Read/write secure system settings with cached fallback to Shizuku/root shell. | +| `getGlobalInt()` / `putGlobalInt()` | `Int` / `Unit` | Read/write global system settings with cached fallback to Shizuku/root shell. | + +--- + +### 2. Android Manifest Registration + +Declare the service inside `` in [`AndroidManifest.xml`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/AndroidManifest.xml) with `BIND_QUICK_SETTINGS_TILE` permission: + +```xml + + + + + + +``` + +--- + +### 3. String Localization + +Declare user-facing tile labels and documentation strings in [`strings.xml`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/res/values/strings.xml): + +```xml + +Feature Name +Enables or disables Feature directly from your Quick Settings shade or widget. +``` + +--- + +### 4. Tile Registry Registration (`QsTileRegistry.kt`) + +Register the tile in [`QsTileRegistry.ALL_TILES`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/java/com/sameerasw/essentials/services/tiles/QsTileRegistry.kt): + +```kotlin +QsTileEntry( + titleRes = R.string.tile_feature_label, + iconRes = R.drawable.rounded_feature_24, + serviceClass = FeatureTileService::class.java +), +``` + +#### Glance Widget Integration: +- `QsTileRegistry` provides state resolution, label translation, dynamic icon rendering, and active status for the **Favorite QS Tiles Glance Widget** ([`QsTilesWidget.kt`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/java/com/sameerasw/essentials/services/widgets/QsTilesWidget.kt)). +- Standard `BaseTileService` subclasses are automatically queried via reflection (`isTileActive`, `getTileSubtitle`, `getTileIcon`). +- If state queries require an external controller (e.g. `CaffeinateController`), add a custom condition in `isTileActive()` / `getTileSubtitle()`. + +--- + +### 5. Headless Action Routing (`QsTileActionRouter.kt`) + +Tapping a tile inside the **Favorite QS Tiles Glance Widget** triggers [`QsTileClickActionCallback`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/java/com/sameerasw/essentials/services/widgets/QsTileClickActionCallback.kt), which dispatches to [`QsTileActionRouter`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/java/com/sameerasw/essentials/services/receivers/QsTileActionRouter.kt): + +- Standard `BaseTileService` subclasses are automatically initialized headlessly by `QsTileActionRouter` to invoke `onTileClick()`. +- If the feature requires broadcast routing or dedicated service intents, define an explicit dispatch branch in `QsTileActionRouter.kt`. + +--- + +### 6. In-App Tile Manager UI (`QuickSettingsTilesSettingsUI.kt`) + +All QS tiles must be added to the in-app Quick Settings Tiles settings screen so users can view permissions and add tiles directly to their system QS panel via `StatusBarManager.requestAddTileService()`. + +In [`QuickSettingsTilesSettingsUI.kt`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/java/com/sameerasw/essentials/ui/features/tiles/QuickSettingsTilesSettingsUI.kt), register the tile in `allTiles`: + +```kotlin +QSTileInfo( + titleRes = R.string.tile_feature_label, + iconRes = R.drawable.rounded_feature_24, + serviceClass = FeatureTileService::class.java, + permissionKeys = listOf("WRITE_SECURE_SETTINGS"), + aboutDescription = R.string.about_desc_feature_tile, + categoryRes = R.string.cat_utils // e.g. R.string.cat_visuals, R.string.cat_privacy, R.string.cat_accessibility +) +``` + +--- + +## Contributor Checklist + +- [ ] **Import Standards**: All package imports declared at the top of the file (no inline package references). +- [ ] **Localization**: User-facing strings added to `strings.xml` with no duplicates. +- [ ] **Iconography**: Rounded drawable resources (`R.drawable.rounded_*`) used. +- [ ] **Permission Handling**: Required permissions correctly mapped in `QSTileInfo` and validated in `hasFeaturePermission()`. +- [ ] **Glance Widget Support**: Tile verified in `QsTilesWidget` (state toggling, label/subtitle display, haptics). +- [ ] **In-App Management**: Tile visible under correct category in `QuickSettingsTilesSettingsUI` with functional "Add" button and "About" dialog. diff --git a/docs/SERVICES_AND_PERMISSIONS.md b/docs/SERVICES_AND_PERMISSIONS.md index e98f6197e..8b0f63d6c 100644 --- a/docs/SERVICES_AND_PERMISSIONS.md +++ b/docs/SERVICES_AND_PERMISSIONS.md @@ -23,3 +23,10 @@ This document outlines background services, Quick Settings tiles, and system per - **`WRITE_SECURE_SETTINGS`**: Granted via ADB (`adb shell pm grant com.sameerasw.essentials android.permission.WRITE_SECURE_SETTINGS`). Allows modifying system secure settings. - **`Shizuku` Binder Interface**: Enables executing privileged system API calls without full root access. - **`Root` (`su`)**: Used for direct kernel sysfs writes (e.g. charging current control, SurfaceFlinger adjustments). + +--- + +## Developer Guide + +For instructions on adding and registering new Quick Settings tiles, refer to [ADD_QS_TILE.md](file:///Users/sameerasandakelum/GIT/essentials/docs/ADD_QS_TILE.md). + From 69b1fde0933d9a2fac3e36998e43d65c3ad565e3 Mon Sep 17 00:00:00 2001 From: sameerasw Date: Wed, 19 Aug 2026 09:23:44 +0530 Subject: [PATCH 2/3] docs: update contribution guidelines --- CONTRIBUTING.md | 137 ++++++++++++++++++++++-------------------------- 1 file changed, 62 insertions(+), 75 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d2d8b7852..a2fac1452 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,102 +1,89 @@ # Contributing to Essentials -Thank you for your interest in contributing to Essentials! This guide will help you set up your development environment and understand the architecture of the project. +Thank you for your interest in contributing to Essentials! This guide details the development setup, architecture conventions, UI component reuse rules, and feature implementation guidelines. + +--- ## Environment Setup -1. **Android Studio**: Download and install the latest version of [Android Studio](https://developer.android.com/studio). -2. **JDK**: Ensure you have JDK 17 or higher installed. -3. **Clone the project**: +1. **Android Studio**: Install the latest stable release of [Android Studio](https://developer.android.com/studio). +2. **JDK**: JDK 17 or higher is required. +3. **Clone Repository**: ```bash git clone https://github.com/sameerasw/essentials.git ``` -4. **Open in Android Studio**: Open the project and wait for Gradle to sync. -5. **Shizuku**: Many features require [Shizuku](https://shizuku.rikka.app/). Install it on your device for testing. - -## Architecture Overview - -Essentials follows a modern Android architecture: - -- **Language**: Kotlin -- **UI Framework**: Jetpack Compose -- **Pattern**: MVVM (Model-View-ViewModel) -- **Dependency Injection**: Manual injection (view models are managed by `MainViewModel` or passed through activities). - -## Feature Implementation Workflow - -Adding a new feature involves three main steps: +4. **Target Branch**: All branches and pull requests must be based on and targeted to merge back into **`develop`**. +5. **Shizuku / Root**: Many privileged features require [Shizuku](https://shizuku.rikka.app/) or Root for testing on your device or emulator. -### 1. Define Metadata in `FeatureRegistry.kt` +--- -All features must be registered in the `FeatureRegistry` object. This centralizes metadata and enables automated search indexing. +## Core Development Guidelines & Principles -```kotlin -object : Feature( - id = "MyNewFeature", - title = "My New Feature", - iconRes = R.drawable.my_feature_icon, - category = "Tools", - description = "A short description of the feature", - permissionKeys = listOf("ACCESSIBILITY"), // Optional - searchableSettings = listOf( - SearchSetting("Option Title", "Description", "highlight_key", listOf("keyword1", "keyword2")) - ) -) { - override fun isEnabled(viewModel: MainViewModel) = viewModel.isMyFeatureEnabled.value - override fun onToggle(viewModel: MainViewModel, context: Context, enabled: Boolean) { - viewModel.setMyFeatureEnabled(enabled, context) - } -} -``` +### 1. Component Reuse (Always Prefer Existing Components) +Before writing custom composables, check the existing design system library in `app/src/main/java/com/sameerasw/essentials/ui/core/`: +- **Containers (`ui/core/containers/`)**: + - `RoundedCardContainer`: Outer container for grouped settings cards (24.dp corner radius, `surfaceContainer` background). + - `RoundedCardLazyContainer`: Container for lazy-scrolling lists. +- **Settings List Items & Cards (`ui/core/cards/`)**: + - `IconToggleItem`: Preferred for settings rows with an icon, title, subtitle/description, and switch. Always pass `index` and `count` for automatic segmented corner morphing. + - `ConfigPickerItem`: For dropdown or modal picker items inside containers. + - `FeatureCard`: High-level feature banner/cards with pastel backgrounds (`ColorUtil.getPastelColorFor`) and vibrant icons (`ColorUtil.getVibrantColorFor`). + - `PermissionCard`: Standardized permission status card with action buttons. +- **Pickers (`ui/core/pickers/`)**: + - `SegmentedPicker`, `MultiSegmentedPicker`: Connected button group pickers with haptic feedback. +- **Bottom Sheets (`ui/core/sheets/`)**: + - `EssentialsBottomSheet`, `PermissionsBottomSheet`, `FeatureHelpBottomSheet`. -### 2. Create the Settings UI +> [!IMPORTANT] +> Do NOT create duplicate ad-hoc cards, custom switches, or non-standard list rows when standard `ui/core/` components already exist. -Create a new composable in `app/src/main/java/com/sameerasw/essentials/ui/composables/configs/`. +--- -- Use `RoundedCardContainer` for grouped items. -- Use `IconToggleItem` or `SimpleToggleItem` for toggles. -- Use `Modifier.highlight(highlightSetting == "key")` to support search highlighting. +### 2. Jetpack Compose & Material 3 Expressive Rules +- **No Inline Package Imports**: Always import classes at the top of the file. Never write inline package paths like `com.sameerasw.essentials.ui.core.cards.IconToggleItem(...)`. +- **Containers & Segmenting**: Group related settings into `RoundedCardContainer`. Never use bare uncontained list items. +- **Material 3 Expressive Theming**: + - Main containers use `surfaceContainer` and `24.dp` rounded corners. + - Sheet dialogs use `surfaceContainerHigh` or `surfaceContainer`. + - Supports dynamic coloring and Pitch Black (pure `#000000` AMOLED) overrides. +- **Disabled State Guidance**: When a feature is disabled or missing permissions, use the `enabled = false` pattern with `onDisabledClick` to launch a guidance sheet rather than hiding controls silently. -### 3. Register in `FeatureSettingsActivity.kt` +--- -Add your new UI to the `when(feature)` block in `FeatureSettingsActivity.kt` to link it to the registration ID. +### 3. Iconography & Strings Localization +- **No Hardcoded Strings**: Never hardcode user-facing strings in UI code. Always add entries to `app/src/main/res/values/strings.xml` and use `stringResource(R.string...)` or `context.getString(R.string...)`. Check before adding to avoid duplicates. +- **Resource Icons**: Always prefer rounded drawable resource icons (`R.drawable.rounded_*`) over vector imports. If an icon is missing during implementation, use the expected `R.drawable.rounded_*` reference. -```kotlin -"MyNewFeature" -> { - MyNewFeatureSettingsUI( - viewModel = viewModel, - modifier = Modifier.padding(top = 16.dp), - highlightSetting = highlightSetting - ) -} -``` +--- -## Search System +### 4. Mandatory Haptics (`HapticUtil`) +- Add haptic feedback on all interactive elements (buttons, switches, sliders, segment pickers, and tiles) using `HapticUtil` (`performUIHaptic`, `performVirtualKeyHaptic`, `performHeavyHaptic`, `performLightHaptic`). +- For background services and Quick Settings tiles, use `HapticUtil.performHapticForService(context)`. -The search system is fully automated. By adding `SearchSetting` objects to your feature in `FeatureRegistry.kt`, they will automatically: +--- -1. Appear in the universal search results. -2. Navigate the user to the correct feature screen. -3. Trigger a pulse animation on the target item via the `highlight` modifier. +### 5. Quick Settings Tiles +- When implementing new Quick Settings tiles, refer to the dedicated guide: [ADD_QS_TILE.md](file:///Users/sameerasandakelum/GIT/essentials/docs/ADD_QS_TILE.md). +- Ensure the tile is declared in `AndroidManifest.xml`, registered in `QsTileRegistry.kt`, supported headlessly in `QsTileActionRouter.kt`, added to `QuickSettingsTilesSettingsUI.kt`, and validated on the **Favorite QS Tiles Glance Widget**. -## Code Style +--- -- Use **PascalCase** for Composables. -- Use **camelCase** for variables and functions. -- Prefer **functional components** and avoid heavy logic in the UI layer. +### 6. Search Integration (`FeatureRegistry.kt`) +- All user-facing settings and toggles must be indexed in `FeatureRegistry.kt` using `SearchSetting(...)` entries. +- UI elements must attach `Modifier.highlight(highlightSetting == "key")` so that universal search results smoothly navigate and highlight the target control. -## Pull Requests +--- -We welcome pull requests! To ensure a smooth review process, please follow these guidelines: +### 7. Code Cleanliness & Comments +- Write clean, idiomatic Kotlin code. +- Avoid conversational, repetitive, or redundant comments. Use concise technical comments only where non-obvious architecture or hardware logic requires explanation. -1. **Create a Branch**: Create a new branch for your feature or bugfix (e.g., `feature/my-new-feature` or `fix/issue-description`). -2. **Keep it Focused**: A PR should ideally do one thing. If you have multiple unrelated changes, please separate them into multiple PRs. -3. **Test Your Changes**: Before submitting, ensure that your changes build correctly and that you've tested them on a physical device or emulator. -4. **Describe Your Work**: In your PR description, explain _what_ you changed and _why_. If your change affects the UI, please include screenshots or a screen recording. -5. **Code Style**: Ensure your code follows the existing style of the project. -6. **Update Documentation**: If you've added a new feature, ensure you've registered it in `FeatureRegistry.kt` as described above so it's searchable. -7. **All to develop**: Please make sure your branches are based on `develop` and also they are set to merge back to `develop` as well. +--- -## Questions? +## Pull Request Workflow -If you have any questions or need help, feel free to open an issue or reach out in our community channels. +1. **Branching**: Create a branch off `develop` (e.g. `feature/my-feature` or `fix/issue-description`). +2. **Target**: Pull requests must target the `develop` branch. +3. **Atomic Scope**: Keep PRs focused on a single feature or bug fix. +4. **Local Verification**: Ensure the project compiles cleanly (`./gradlew assembleDebug`) and passes testing on a physical device or emulator. +5. **PR Description**: Detail the rationale, changes made, and include screenshots or screen recordings for any UI changes. From 4b1c9cb8aa82e4a4cd19f9a210c36c288931223c Mon Sep 17 00:00:00 2001 From: sameerasw Date: Wed, 19 Aug 2026 09:28:17 +0530 Subject: [PATCH 3/3] docs: updated contribution guidelines --- CONTRIBUTING.md | 129 +++++++++++++++++++++++++++++++----------------- 1 file changed, 84 insertions(+), 45 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a2fac1452..f0143da96 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,89 +1,128 @@ # Contributing to Essentials -Thank you for your interest in contributing to Essentials! This guide details the development setup, architecture conventions, UI component reuse rules, and feature implementation guidelines. +Thank you for your interest in contributing to Essentials! This guide details the development setup, architectural conventions, state management patterns, UI component reuse guidelines, service decoupling practices, and pull request workflows. --- ## Environment Setup -1. **Android Studio**: Install the latest stable release of [Android Studio](https://developer.android.com/studio). -2. **JDK**: JDK 17 or higher is required. +1. **Android Studio**: Use the latest stable release of [Android Studio](https://developer.android.com/studio). +2. **JDK**: Use JDK 17 or higher. 3. **Clone Repository**: ```bash git clone https://github.com/sameerasw/essentials.git ``` -4. **Target Branch**: All branches and pull requests must be based on and targeted to merge back into **`develop`**. +4. **Target Branch**: Ensure all branches and pull requests are based on and targeted to merge back into **`develop`**. 5. **Shizuku / Root**: Many privileged features require [Shizuku](https://shizuku.rikka.app/) or Root for testing on your device or emulator. --- -## Core Development Guidelines & Principles +## Core Architectural & Development Principles -### 1. Component Reuse (Always Prefer Existing Components) -Before writing custom composables, check the existing design system library in `app/src/main/java/com/sameerasw/essentials/ui/core/`: +### 1. State Management & ViewModel Integration +- **Complete End-to-End Pipeline**: Ensure any new UI control or `FeatureRegistry.kt` entry is backed by a complete state flow: + - Provide typed getter and setter methods in [`SettingsRepository`](file:///Users/sameerasandakelum/GIT/essentials/app/src/main/java/com/sameerasw/essentials/data/repository/SettingsRepository.kt). + - Expose reactive state (`mutableStateOf`) and mutator functions in the corresponding ViewModel (e.g. `MainViewModel`, `NetworksViewModel`). + - Connect the UI composable and `FeatureRegistry.onToggle` directly to these ViewModel methods. +- **Centralized Preference Keys**: Define all preference keys and helper accessors inside `SettingsRepository` to keep keys uniform and discoverable. +- **Database & Persistent Properties**: Maintain clean migrations for persistent properties to preserve built-in configuration export and import integrity. + +--- + +### 2. Service Decoupling & Modularity +- **Preserve Shared Services**: Keep shared background services (such as `ScreenOffAccessibilityService`) lightweight and focused on their core responsibilities. +- **Use Dedicated Handlers & Controllers**: + - Encapsulate feature-specific listeners (e.g. connectivity changes, sensor observers, audio events) in dedicated controllers or handlers under `domain/controller/` or `services/handlers/`. + - Connect external events to shared services through clean adapters or listeners to maintain clear separation of concerns. + +--- + +### 3. Privileged Execution & Error Feedback +- **Transparent Execution**: When executing shell commands (`ShellUtils.runCommand`), system APIs, or Shizuku binders: + - Check command return codes and handle permission exceptions gracefully. + - Provide clear UI feedback (such as guidance sheets, permission cards, or status indicators) if privileged execution cannot be completed. +- **Pre-Flight Permission Checks**: Verify required permissions (`WRITE_SECURE_SETTINGS`, Shizuku, Root, Accessibility) before initiating restricted actions. + +--- + +### 4. Component Reuse & Design System +Leverage the rich design system components in `app/src/main/java/com/sameerasw/essentials/ui/core/` to maintain a consistent Material 3 Expressive interface: - **Containers (`ui/core/containers/`)**: - - `RoundedCardContainer`: Outer container for grouped settings cards (24.dp corner radius, `surfaceContainer` background). - - `RoundedCardLazyContainer`: Container for lazy-scrolling lists. -- **Settings List Items & Cards (`ui/core/cards/`)**: - - `IconToggleItem`: Preferred for settings rows with an icon, title, subtitle/description, and switch. Always pass `index` and `count` for automatic segmented corner morphing. - - `ConfigPickerItem`: For dropdown or modal picker items inside containers. - - `FeatureCard`: High-level feature banner/cards with pastel backgrounds (`ColorUtil.getPastelColorFor`) and vibrant icons (`ColorUtil.getVibrantColorFor`). - - `PermissionCard`: Standardized permission status card with action buttons. + - `RoundedCardContainer`: Use for grouping related settings items. + - `RoundedCardLazyContainer`: Use for scrolling list containers. +- **Cards & Settings Items (`ui/core/cards/`)**: + - `IconToggleItem`: Use for standard toggle rows with an icon, title, description, and switch. Always supply `index` and `count` for seamless shape morphing. + - `ConfigPickerItem`: Use for settings rows opening picker dialogs or bottom sheets. + - `FeatureCard`: Use for highlighted feature banners using pastel background palettes (`ColorUtil.getPastelColorFor`) and vibrant icons (`ColorUtil.getVibrantColorFor`). + - `PermissionCard`: Use for consistent permission status displays and action triggers. - **Pickers (`ui/core/pickers/`)**: - - `SegmentedPicker`, `MultiSegmentedPicker`: Connected button group pickers with haptic feedback. + - `SegmentedPicker`, `MultiSegmentedPicker`: Use for connected button groups with built-in tactile feedback. - **Bottom Sheets (`ui/core/sheets/`)**: - - `EssentialsBottomSheet`, `PermissionsBottomSheet`, `FeatureHelpBottomSheet`. + - `EssentialsBottomSheet`, `PermissionsBottomSheet`, `FeatureHelpBottomSheet`: Use for modal sheets and feature guidance. -> [!IMPORTANT] -> Do NOT create duplicate ad-hoc cards, custom switches, or non-standard list rows when standard `ui/core/` components already exist. +> [!TIP] +> Always check `ui/core/` before creating custom cards, list items, or containers to ensure visual harmony and maintainability. --- -### 2. Jetpack Compose & Material 3 Expressive Rules -- **No Inline Package Imports**: Always import classes at the top of the file. Never write inline package paths like `com.sameerasw.essentials.ui.core.cards.IconToggleItem(...)`. -- **Containers & Segmenting**: Group related settings into `RoundedCardContainer`. Never use bare uncontained list items. +### 5. Jetpack Compose & Material 3 Expressive Conventions +- **Top-Level Package Imports**: Place all class and symbol imports at the top of the file and reference items by their simple names. +- **Structured Grouping**: Group related settings into `RoundedCardContainer` blocks to maintain visual hierarchy. - **Material 3 Expressive Theming**: - - Main containers use `surfaceContainer` and `24.dp` rounded corners. - - Sheet dialogs use `surfaceContainerHigh` or `surfaceContainer`. - - Supports dynamic coloring and Pitch Black (pure `#000000` AMOLED) overrides. -- **Disabled State Guidance**: When a feature is disabled or missing permissions, use the `enabled = false` pattern with `onDisabledClick` to launch a guidance sheet rather than hiding controls silently. + - Use `surfaceContainer` for outer card containers and `surfaceContainerHigh` for modal bottom sheets. + - Ensure compatibility with Dynamic Color and Pitch Black (pure `#000000` AMOLED) token palettes. +- **Supportive Disabled States**: When a feature is inactive or missing requirements, use `enabled = false` paired with `onDisabledClick` to present an explanatory guidance sheet. + +--- + +### 6. Iconography & String Localization +- **String Resources**: Place all user-visible text in `app/src/main/res/values/strings.xml` and access them via `stringResource(R.string...)` or `context.getString(R.string...)`. Check existing entries first to avoid duplicates. +- **Drawable Resources**: Use rounded drawable resources (`R.drawable.rounded_*`) across UI elements and Quick Settings tiles. --- -### 3. Iconography & Strings Localization -- **No Hardcoded Strings**: Never hardcode user-facing strings in UI code. Always add entries to `app/src/main/res/values/strings.xml` and use `stringResource(R.string...)` or `context.getString(R.string...)`. Check before adding to avoid duplicates. -- **Resource Icons**: Always prefer rounded drawable resource icons (`R.drawable.rounded_*`) over vector imports. If an icon is missing during implementation, use the expected `R.drawable.rounded_*` reference. +### 7. Tactile Haptic Feedback (`HapticUtil`) +- **Interactive UI Feedback**: Integrate appropriate haptic responses on buttons, switches, sliders, segment pickers, and tiles using `HapticUtil` (`performUIHaptic`, `performVirtualKeyHaptic`, `performHeavyHaptic`, `performLightHaptic`). +- **Background & Tile Actions**: Use `HapticUtil.performHapticForService(context)` inside background services and QS tile interactions. +- **Feature Haptic Preferences**: Respect user-configured haptic profiles when available. --- -### 4. Mandatory Haptics (`HapticUtil`) -- Add haptic feedback on all interactive elements (buttons, switches, sliders, segment pickers, and tiles) using `HapticUtil` (`performUIHaptic`, `performVirtualKeyHaptic`, `performHeavyHaptic`, `performLightHaptic`). -- For background services and Quick Settings tiles, use `HapticUtil.performHapticForService(context)`. +### 8. Quick Settings Tile Integration +- Follow the step-by-step developer guide in [ADD_QS_TILE.md](file:///Users/sameerasandakelum/GIT/essentials/docs/ADD_QS_TILE.md) when adding new tiles. +- Declare the service in `AndroidManifest.xml`, register in `QsTileRegistry.kt`, support headless execution in `QsTileActionRouter.kt`, list in `QuickSettingsTilesSettingsUI.kt`, and test on the **Favorite QS Tiles Glance Widget**. --- -### 5. Quick Settings Tiles -- When implementing new Quick Settings tiles, refer to the dedicated guide: [ADD_QS_TILE.md](file:///Users/sameerasandakelum/GIT/essentials/docs/ADD_QS_TILE.md). -- Ensure the tile is declared in `AndroidManifest.xml`, registered in `QsTileRegistry.kt`, supported headlessly in `QsTileActionRouter.kt`, added to `QuickSettingsTilesSettingsUI.kt`, and validated on the **Favorite QS Tiles Glance Widget**. +### 9. Universal Search Integration (`FeatureRegistry.kt`) +- Register configurable settings in `FeatureRegistry.kt` using `SearchSetting(...)` entries. +- Attach `Modifier.highlight(highlightSetting == "key")` to composables so universal search can smoothly navigate to and highlight target items. --- -### 6. Search Integration (`FeatureRegistry.kt`) -- All user-facing settings and toggles must be indexed in `FeatureRegistry.kt` using `SearchSetting(...)` entries. -- UI elements must attach `Modifier.highlight(highlightSetting == "key")` so that universal search results smoothly navigate and highlight the target control. +### 10. Code Style & Technical Documentation +- Write clean, concise, and idiomatic Kotlin. +- Use clear, technical comments where complex architecture, system settings, or low-level hardware interactions benefit from explanation. --- -### 7. Code Cleanliness & Comments -- Write clean, idiomatic Kotlin code. -- Avoid conversational, repetitive, or redundant comments. Use concise technical comments only where non-obvious architecture or hardware logic requires explanation. +## Best Practices Reference + +| Area | Recommended Pattern | Context | +| :--- | :--- | :--- | +| **ViewModel State** | Expose reactive states via `SettingsRepository` and ViewModel methods | Ensures clean compilation, predictable state flow, and working search toggles. | +| **Background Logic** | Encapsulate features in modular handlers under `domain/controller/` | Keeps shared services (e.g. accessibility service) clean and isolated. | +| **Import Hygiene** | Place all package imports at the top of the file | Keeps code readable and conforms to project styling conventions. | +| **Preferences** | Store and access keys through constants in `SettingsRepository` | Prevents typos and centralizes data contracts. | +| **Privilege Feedback** | Validate permissions and provide clear UI feedback on failures | Keeps users informed when elevated permissions are needed. | +| **UI Components** | Use `RoundedCardContainer`, `IconToggleItem`, and `ui/core/` composables | Preserves design consistency and built-in shape morphing across all screens. | --- ## Pull Request Workflow -1. **Branching**: Create a branch off `develop` (e.g. `feature/my-feature` or `fix/issue-description`). -2. **Target**: Pull requests must target the `develop` branch. -3. **Atomic Scope**: Keep PRs focused on a single feature or bug fix. -4. **Local Verification**: Ensure the project compiles cleanly (`./gradlew assembleDebug`) and passes testing on a physical device or emulator. -5. **PR Description**: Detail the rationale, changes made, and include screenshots or screen recordings for any UI changes. +1. **Branching**: Create a feature or fix branch from `develop` (e.g. `feature/my-feature` or `fix/issue-description`). +2. **Target**: Point all pull requests to the `develop` branch. +3. **Focused Scope**: Keep changes cohesive and centered around a single feature or bug fix. +4. **Local Verification**: Verify the build compiles smoothly (`./gradlew assembleDebug`) and test functionality on a physical device or emulator. +5. **PR Description**: Include a clear summary of changes, rationale, and screenshots/recordings for any UI updates.