Skip to content

ADFA-2206: Fix NPE in asset installation when zip entry is missing#699

Merged
Daniel-ADFA merged 5 commits intostagefrom
ADFA-2206
Dec 10, 2025
Merged

ADFA-2206: Fix NPE in asset installation when zip entry is missing#699
Daniel-ADFA merged 5 commits intostagefrom
ADFA-2206

Conversation

@Daniel-ADFA
Copy link
Contributor

No description provided.

@Daniel-ADFA Daniel-ADFA requested a review from a team December 4, 2025 20:54
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 4, 2025

Greptile Overview

Greptile Summary

This PR fixes a NullPointerException in SplitAssetsInstaller.doInstall() that occurred when a requested entry was not found in the assets zip file. The fix adds an elvis operator with a FileNotFoundException throw after the zipFile.getEntry(entryName) call, preventing the NPE that would occur when passing null to zipFile.getInputStream().

  • Added null check for zip entry lookup with descriptive error message
  • Exception is properly caught by existing error handling in AssetsInstallationHelper.install() via runCatching
  • Follows the same pattern used in preInstall() for the zip file existence check

Confidence Score: 5/5

  • This PR is safe to merge - it adds defensive null checking that improves error handling without changing existing behavior.
  • The change is minimal, defensive, and follows existing patterns in the codebase. It converts a potential NPE into a descriptive FileNotFoundException which is already handled by the caller. No regression risk.
  • No files require special attention.

Important Files Changed

File Analysis

Filename Score Overview
app/src/main/java/com/itsaky/androidide/assets/SplitAssetsInstaller.kt 5/5 Adds null check after zipFile.getEntry() to throw FileNotFoundException instead of NPE when entry is missing from the zip file.

Sequence Diagram

sequenceDiagram
    participant AH as AssetsInstallationHelper
    participant SAI as SplitAssetsInstaller
    participant ZF as ZipFile

    AH->>SAI: doInstall(context, stagingDir, cpuArch, entryName)
    SAI->>ZF: getEntry(entryName)
    alt Entry exists
        ZF-->>SAI: ZipEntry
        SAI->>ZF: getInputStream(entry)
        ZF-->>SAI: InputStream
        SAI->>SAI: Process entry based on type
        SAI-->>AH: Success
    else Entry missing (NEW FIX)
        ZF-->>SAI: null
        SAI->>SAI: throw FileNotFoundException
        SAI-->>AH: Exception propagates
        AH->>AH: Caught by runCatching
        AH-->>AH: Result.Failure returned
    end
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, no comments

Edit Code Review Agent Settings | Greptile

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 10, 2025

📝 Walkthrough

Release Notes - ADFA-2206: Fix NPE in asset installation when zip entry is missing

Changes

  • Null-check for ZIP entries: Added proper null-check in asset installation when ZIP entries are missing, throwing a localized FileNotFoundException with message "Entry '%1$s' not found in assets zip file"
  • Error message architecture shift: Transitioned from string resource IDs (@stringres Int) to dynamic error message strings throughout error handling
  • AssetsInstallationHelper enhancement: Added errorMessage property to Failure data class to provide derived error messages from exceptions
  • Progress job lifecycle management: Improved PermissionsFragment with explicit progress job cancellation in finally block to prevent resource leaks
  • Simplified error state: Removed flashError call during installation error state for cleaner error handling flow

⚠️ Risks and Best Practices Violations

  • BREAKING API CHANGE: InstallationError constructor parameter changed from Int errorMessageResId (@stringres) to String errorMessage. All code instantiating this class must be updated.

  • Localization Risk: Shifted from guaranteed translated string resources to dynamic exception messages. Not all exception messages are guaranteed to be properly localized, potentially exposing users to untranslated or cryptic error text.

  • Inconsistent error messaging: Reliance on exception.cause?.message for error display assumes causes always provide meaningful, user-friendly text. Fallback behavior and message quality not clearly documented.

  • Nullable error message handling: errorMessage derived from cause?.message may be nullable in Failure - usage patterns need verification to ensure null-safety.

✓ Positive Changes

  • Proper resource cleanup with progress job cancellation in finally block demonstrates good coroutine lifecycle management
  • Fixes potential NullPointerException that could crash asset installation

Walkthrough

Refactor of the installation error handling system to propagate concrete error message strings instead of resource identifiers. Changes span the error state model, installer components, viewmodel error handling, and UI fragment progress management.

Changes

Cohort / File(s) Summary
Error State Model
app/src/main/java/com/itsaky/androidide/viewmodel/InstallationState.kt
Changed InstallationError data class to accept a String errorMessage parameter instead of an Int errorMessageResId. Removed @StringRes annotation and associated import.
Asset Installation Error Handling
app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt, app/src/main/java/com/itsaky/androidide/assets/SplitAssetsInstaller.kt, resources/src/main/res/values/strings.xml
Added errorMessage property to Failure data class in AssetsInstallationHelper. Added null-check in SplitAssetsInstaller.doInstall() to raise FileNotFoundException with localized message when ZIP entry is missing. Added new string resource err_asset_entry_not_found for missing entry error messaging.
ViewModel Error Propagation
app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt
Updated error handling paths to compute concrete error message strings and propagate via UI events. On AssetsInstallationHelper.Result.Failure, derives error message and emits ShowError with the message. On exceptions, constructs error message from exception or default and updates InstallationError with the string value.
UI Fragment Progress Management
app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt
Removed flashError call in InstallationError state handler. Introduced progressJob coroutine on Main dispatcher to collect setup progress updates. Wrapped state-waiting logic in try-finally block to ensure progressJob cancellation on flow exit.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • InstallationViewModel.kt: Error message construction logic across multiple failure paths requires verification that fallback behavior and exception-to-message conversion is sound
  • PermissionsFragment.kt: Progress job lifecycle management in try-finally block should be verified for proper cancellation and no resource leaks
  • SplitAssetsInstaller.kt: New null-check validity and localized error message propagation chain

Poem

🐰 Errors now speak their minds so clear,
No cryptic IDs to fill you with fear—
Concrete messages flow through the line,
With progress tracked and state divine! 🎯

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive No pull request description was provided by the author, making it impossible to assess relevance to the changeset. Add a description explaining the changes, such as the NPE fix in zip entry lookup and related refactoring of error handling.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: fixing a null pointer exception (NPE) in asset installation when a zip entry is missing, which aligns with the primary code change in SplitAssetsInstaller.kt.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ADFA-2206

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt (2)

92-99: Consider simplifying the event emission.

The nested viewModelScope.launch inside the withContext(Dispatchers.IO) block is unnecessary. Since emit() is a suspend function and MutableSharedFlow is thread-safe, you can call it directly without launching a new coroutine.

 							is AssetsInstallationHelper.Result.Failure -> {
 								result.cause?.let { Sentry.captureException(it) }
 								val errorMsg = result.errorMessage
 									?: context.getString(R.string.title_installation_failed)
-								viewModelScope.launch {
-									_events.emit(InstallationEvent.ShowError(errorMsg))
-								}
+								_events.emit(InstallationEvent.ShowError(errorMsg))
 								_state.update {
 									InstallationError(errorMsg)
 								}
 							}

106-112: Same simplification applies here.

The nested launch in the exception handler can also be removed.

 				} catch (e: Exception) {
 					Sentry.captureException(e)
 					log.error("IDE setup installation failed", e)
 					val errorMsg = e.message ?: context.getString(R.string.unknown_error)
-					viewModelScope.launch {
-						_events.emit(InstallationEvent.ShowError(errorMsg))
-					}
+					_events.emit(InstallationEvent.ShowError(errorMsg))
 					_state.update {
 						InstallationError(errorMsg)
 					}
 				}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32c5aab and c3be4c1.

📒 Files selected for processing (6)
  • app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt (1 hunks)
  • app/src/main/java/com/itsaky/androidide/assets/SplitAssetsInstaller.kt (2 hunks)
  • app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt (2 hunks)
  • app/src/main/java/com/itsaky/androidide/viewmodel/InstallationState.kt (1 hunks)
  • app/src/main/java/com/itsaky/androidide/viewmodel/InstallationViewModel.kt (1 hunks)
  • resources/src/main/res/values/strings.xml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt (1)
app/src/main/java/com/itsaky/androidide/fragments/debug/Resolvable.kt (1)
  • withContext (77-78)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build Universal APK
🔇 Additional comments (5)
app/src/main/java/com/itsaky/androidide/assets/AssetsInstallationHelper.kt (1)

49-52: LGTM! Good enhancement to error propagation.

The addition of errorMessage with a sensible default derived from the cause provides flexibility for callers to either use the automatic message or supply a custom one (as done in SplitAssetsInstaller).

resources/src/main/res/values/strings.xml (1)

47-47: LGTM!

Clear, descriptive error message with proper format placeholder for the missing entry name.

app/src/main/java/com/itsaky/androidide/assets/SplitAssetsInstaller.kt (1)

48-49: LGTM! This is the core fix for the NPE.

The null check prevents the NullPointerException that would occur when zipFile.getEntry(entryName) returns null and subsequent code attempts to use it. The localized error message provides clear feedback to users about which entry is missing.

app/src/main/java/com/itsaky/androidide/fragments/onboarding/PermissionsFragment.kt (1)

222-247: LGTM! Good structured concurrency improvement.

The try/finally block ensures the progressJob is properly cancelled regardless of how the flow exits (success, error, or exception). This prevents potential resource leaks from orphaned coroutines.

app/src/main/java/com/itsaky/androidide/viewmodel/InstallationState.kt (1)

13-13: LGTM!

Changing from resource ID to concrete string enables dynamic error messages that can include runtime values (like the missing entry name). This flexibility is essential for the NPE fix's error reporting.

@Daniel-ADFA Daniel-ADFA merged commit 6d38d96 into stage Dec 10, 2025
2 checks passed
@Daniel-ADFA Daniel-ADFA deleted the ADFA-2206 branch December 10, 2025 14:07
avestaadfa added a commit that referenced this pull request Dec 15, 2025
* ADFA-2164 | Prevent crash when loading invalid font files (#650)

* fix: prevent crash when loading invalid font files
Add validation and UI warnings for empty or corrupt font files.

* refactor(layouteditor): Change threads handling, add magic constants and Log exception

* refactor(layouteditor): Address bot comments, first valid then copy file, initialize executor and shutdown in onDestroyView

* fix(fonts): validate before copy and avoid broken UI entries

* refactor(strings): add a descriptive error message

* Implement On-Demand Loading for Llama Module from Assets (#491)

* feat: Integrate llama.cpp as a new module

This commit introduces a new `:llama` Android library module that integrates the `llama.cpp` library for local large language model inference.

The module provides a `LLamaAndroid` Kotlin class, which acts as a singleton wrapper around the native `llama.cpp` functions via JNI. This enables loading models, managing contexts, tokenizing text, and running inference.

Key changes:
- **Module Creation:** Added a new `:llama` library module with its own Gradle build files (`build.gradle.kts`), ProGuard rules, and Android Manifest.
- **Native Integration:**
    - Included a `CMakeLists.txt` to build `llama.cpp` from a local source directory.
    - Added `llama-android.cpp` which contains the JNI bridge between Kotlin and the native C++ functions.
    - Implemented native functions for model/context/batch/sampler management, tokenization, inference (`completion_init`, `completion_loop`), and benchmarking.
    - Configured `llama_log_set` to redirect native logs to Android's Logcat.
- **Kotlin Wrapper (`LLamaAndroid.kt`):**
    - Created a singleton `LLamaAndroid` class to manage the lifecycle of the native llama.cpp objects.
    - Exposed high-level functions like `load()`, `unload()`, `send()`, `tokenize()`, and `bench()`.
    - Manages native state on a dedicated single-threaded coroutine dispatcher to ensure thread safety.
- **Build Configuration:**
    - Added `:llama` as a dependency to the main `:app` module and included it in `settings.gradle.kts`.
    - Configured CMake arguments in `llama/build.gradle.kts` to customize the `llama.cpp` build (e.g., disabling CURL).
- **Bug Fixes & Improvements:**
    - Increased the `n_batch` size to 2048 in `LLamaAndroid.kt` to prevent failures with larger contexts.
    - Corrected the implementation of the `tokenize` JNI function to use the `common_tokenize` helper, ensuring consistency.
    - Added a repetition penalty sampler to the default sampler chain in the C++ code to improve text generation quality.

* refactor: Use relative path for llama.cpp submodule

This commit updates the `CMakeLists.txt` file to use a relative path instead of a hardcoded absolute path for the `llama.cpp` dependency.

This change makes the build process portable and independent of the local user's directory structure. The `llama.cpp` source is now expected to be located in `subprojects/llama.cpp/`.

* refactor: Use relative path for llama.cpp submodule

This commit updates the `CMakeLists.txt` file to use a relative path instead of a hardcoded absolute path for the `llama.cpp` dependency.

This change makes the build process portable and independent of the local user's directory structure. The `llama.cpp` source is now expected to be located in `subprojects/llama.cpp/`.

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* COmments

* COmments

* working

* refactor

* refactor(agent): Improve Local LLM Repository and agentic loop

This commit refactors the local LLM implementation by moving the inference logic into a dedicated `LlmInferenceEngine` object within the `repository` package.

Key changes:
- **New `LlmInferenceEngine`:** A new singleton object in the `agent.repository` package now manages the `LLamaAndroid` instance, including model loading, unloading, and inference. This replaces the deleted `LlmInterfaceEngine` from the `app` package.
- **Improved Agentic Loop:** The agentic loop in `LocalLlmRepositoryImpl` is now more robust. It correctly formats history for the model, adds the model's raw response to the history for better context, and continues the loop when tool call parsing fails.
- **Refined System Prompt:** The system prompt is clearer, instructing the model to use `[TOOL_CALL]` markers and providing a better example. Tool definitions are also formatted more cleanly.
- **`generateCode` Implementation:** Implemented the `generateCode` function to allow code generation with the local LLM.
- **Lenient JSON Parsing:** The JSON parser is now configured to be lenient to better handle malformed JSON output from the model.

* feat(agent): Add support for local LLM backend

This change introduces a switchable backend system for the AI Agent, allowing users to choose between the existing Gemini API and a new local LLM backend.

The `ChatViewModel` has been refactored to initialize the appropriate AI repository (`AgenticRunner` for Gemini or `LocalLlmRepositoryImpl` for local models) on-demand when a message is sent. This removes the previous one-time initialization logic and allows the backend to be switched dynamically.

The `AiSettingsFragment` is updated to:
- Allow users to select their preferred AI backend (Gemini or Local LLM).
- Provide a file picker for users to select a local model file when the Local LLM backend is chosen.
- The UI now dynamically shows settings relevant to the selected backend.

* binding

* binding

* loading

* Model loaded successfully

* info from settings

* feat(ai): Synchronize model loading state between UI and engine

This commit refactors the local AI model loading logic to ensure the UI state (`AiSettingsViewModel`) is always synchronized with the underlying inference engine (`LlmInferenceEngine`).

Key changes:
- `LlmInferenceEngine` now tracks the loaded model's name and status.
- The `getFileNameFromUri` helper function is moved into `LlmInferenceEngine` to keep state management self-contained.
- `AiSettingsViewModel` now checks the engine's status on startup (`checkInitialSavedModel`) to correctly reflect an already-loaded model in the UI, preventing the need for the user to reload it.
- Model loading in the ViewModel is simplified to directly sync its state from the engine after a load attempt.

* feat(agent): Add backend status indicator to chat screen

This commit introduces a UI element on the chat screen to display the currently active AI backend (e.g., Gemini or a local model's filename). This replaces the previous "Agent Mode" dropdown menu.

Key changes:
- Adds a backend status view in `fragment_chat.xml` which includes an icon and text to show the current AI backend.
- Removes the now-unused "Agent Mode" dropdown menu.
- In `ChatViewModel`, logic is added to format and expose the backend display text via `LiveData`.
- The view model now updates this status display continuously when the fragment is resumed, in addition to showing a one-time system message when the backend is changed.

* feat(agent): Implement cooperative cancellation for agent tasks

This change introduces a robust mechanism to stop ongoing AI agent tasks, including local LLM inference and agentic workflows.

Key changes:
- A `stop()` method has been added to the `GeminiRepository` interface and implemented across all relevant repositories (`LocalLlmRepositoryImpl`, `AgenticRunner`, `SwitchableGeminiRepository`).
- The native `LLamaAndroid` class now includes a `stop()` method that sets an atomic flag, allowing the inference loop to terminate cooperatively.
- `AgenticRunner` now uses a cancellable `CoroutineScope` to manage its lifecycle, allowing its execution loop to be interrupted.
- `ChatViewModel`'s `stopAgentResponse()` method now calls both `agentRepository.stop()` and cancels the coroutine job to ensure a fast and clean shutdown of the agent task.
- Error handling in `ChatViewModel` is improved to manage cancellations gracefully and reset the agent's state.

* feat(agent): Implement cooperative cancellation for agent tasks

This change introduces a robust mechanism to stop ongoing AI agent tasks, including local LLM inference and agentic workflows.

Key changes:
- A `stop()` method has been added to the `GeminiRepository` interface and implemented across all relevant repositories (`LocalLlmRepositoryImpl`, `AgenticRunner`, `SwitchableGeminiRepository`).
- The native `LLamaAndroid` class now includes a `stop()` method that sets an atomic flag, allowing the inference loop to terminate cooperatively.
- `AgenticRunner` now uses a cancellable `CoroutineScope` to manage its lifecycle, allowing its execution loop to be interrupted.
- `ChatViewModel`'s `stopAgentResponse()` method now calls both `agentRepository.stop()` and cancels the coroutine job to ensure a fast and clean shutdown of the agent task.
- Error handling in `ChatViewModel` is improved to manage cancellations gracefully and reset the agent's state.

* Refactor(agent): Improve local LLM agentic loop and tool handling

This commit introduces several key improvements to the local Large Language Model (LLM) agent:

-   **Refactors Tool Execution**: The `Tool.execute` method's argument type is changed from `Map<String, Any>` to `Map<String, JsonElement>` for better type safety and consistency with JSON parsing.
-   **Improves Agentic Loop**: The agentic loop in `LocalLlmRepositoryImpl` is significantly enhanced. It now builds a more structured prompt history, manages conversation state, and uses stop strings to better control model output and detect the end of tool calls.
-   **Enhances Tool Parsing**: A new `parseToolCall` function replaces the previous regex-based approach. It now uses `JSONObject` for more robust parsing of `<tool_call>` blocks from the model's output.
-   **Removes Unused Code**: The `SwitchableGeminiRepository` class, which was responsible for switching between different AI backends, has been entirely removed as it is no longer in use. Cleaned up comments in `AgenticRunner`.
-   **Adds Stop String to Inference**: The `LlmInferenceEngine.runInference` method now accepts a list of stop strings, allowing more fine-grained control over the generation process.

* feat(agent): Show intermediate progress for local LLM and Gemini

This change introduces an `onProgressUpdate` callback to show intermediate steps from the AI agent in the chat UI.

The `GeminiRepository` and `AgenticRunner` interfaces now include the optional `onProgressUpdate` callback.

In `ChatViewModel`, this callback is implemented for both `AgenticRunner` and `LocalLlmRepositoryImpl` to add progress messages directly to the current chat session.

The `LocalLlmRepositoryImpl` has been refactored to leverage this new callback. It now sends back "thought" processes, tool calls, and tool results as system messages during its agentic loop. This removes the need for the repository to manage its own internal UI message list, simplifying its logic and providing real-time updates to the user.

* feat(agent): Add timers to track agent operation duration

This commit introduces timers to measure and display the total and step-by-step duration of AI agent operations.

- A new `onStateUpdate` callback is added to the agent repositories (`AgenticRunner`, `LocalLlmRepositoryImpl`) to listen for state changes.
- The `ChatViewModel` now starts a timer when an agent operation begins and stops it upon completion.
- A `resetStepTimer()` function is called whenever the agent enters a new `Processing` state, allowing for tracking the duration of individual steps.

* feat(agent): Add timers to track agent operation duration

This commit introduces timers to measure and display the total and step-by-step duration of AI agent operations.

- A new `onStateUpdate` callback is added to the agent repositories (`AgenticRunner`, `LocalLlmRepositoryImpl`) to listen for state changes.
- The `ChatViewModel` now starts a timer when an agent operation begins and stops it upon completion.
- A `resetStepTimer()` function is called whenever the agent enters a new `Processing` state, allowing for tracking the duration of individual steps.

* feat(chat): Replace placeholder message with new message

Instead of updating the "thinking..." placeholder message with the agent's response, remove the placeholder and add the agent's response as a new message. This ensures the new message appears at the bottom of the chat, improving the user experience.

* feat(agent): Add collapsible system messages

This commit introduces a separate, collapsible view type for system and tool messages in the agent chat.

Key changes:
- Created a new `list_item_chat_system_message.xml` layout for system messages, featuring an expandable/collapsible header.
- Added new icons (`ic_robot`, `ic_expand_more`) for the system message view.
- Modified `ChatAdapter` to support multiple view types (`VIEW_TYPE_DEFAULT` and `VIEW_TYPE_SYSTEM`).
- Implemented `SystemMessageViewHolder` to handle the binding and expand/collapse logic for system messages.
- Added an `isExpanded` state to the `ChatMessage` data class to manage the visibility of system message content.
- Updated `DiffCallback` to ensure smooth animations when the `isExpanded` state changes.

* feat(agent): Add collapsible system messages

This commit introduces a separate, collapsible view type for system and tool messages in the agent chat.

Key changes:
- Created a new `list_item_chat_system_message.xml` layout for system messages, featuring an expandable/collapsible header.
- Added new icons (`ic_robot`, `ic_expand_more`) for the system message view.
- Modified `ChatAdapter` to support multiple view types (`VIEW_TYPE_DEFAULT` and `VIEW_TYPE_SYSTEM`).
- Implemented `SystemMessageViewHolder` to handle the binding and expand/collapse logic for system messages.
- Added an `isExpanded` state to the `ChatMessage` data class to manage the visibility of system message content.
- Updated `DiffCallback` to ensure smooth animations when the `isExpanded` state changes.

* feat: Show preview for collapsed system logs

Adds a single-line preview for collapsed system log messages in the chat. This provides users with context about the log's content without needing to expand it.

When collapsed, the system message header now displays "Log: " followed by a cleaned-up, single-line version of the markdown content. When expanded, it reverts to the simple "System Log" title.

* feat(logging): Replace Android Log with SLF4J

Replaces the Android `Log` utility with SLF4J for structured and more robust logging across the `llama` and `app` modules.

This change introduces the SLF4J dependency and refactors the logging calls in `LLamaAndroid` and `LlmInferenceEngine` to use the new framework. This improves logging consistency and removes unnecessary comments and KDoc.

* feat: Bridge native llama.cpp logs to slf4j

Introduces a JNI bridge to forward logs from the native `llama.cpp` layer to the Kotlin/Java side, utilizing the slf4j logging framework.

This change replaces the direct `__android_log_print` calls with a more robust logging mechanism. It correctly handles JNI thread attachment and detachment to prevent crashes, ensuring that native logs are properly surfaced within the Android application's logging system.

* feat: Add specific C++ to Kotlin info logging

Introduces a new C++ function `log_info_to_kt` to send formatted `INFO` level logs directly to the Kotlin bridge. This is used to replace a general `LOGi` call for more specific logging of token caching details.

The `LLamaAndroid.kt` file is also cleaned up by removing a redundant comment.

* Refactor: Move `getFileNameFromUri` to Uri extension and remove unused code

This commit refactors the codebase by:
- Moving the duplicated `getFileNameFromUri` function into a `getFileName` extension function on the `Uri` class within `common/src/main/java/com/itsaky/androidide/utils/UriExtensions.kt`.
- Updating all call sites to use the new extension function.
- Removing the unused `TOOL` enum value from `ChatMessage.Sender`.
- Simplifying the tool call parsing logic in `LocalLlmRepositoryImpl` by using Kotlinx Serialization instead of manual JSON parsing.

* Refactor: Move `getFileNameFromUri` to Uri extension and remove unused code

This commit refactors the codebase by:
- Moving the duplicated `getFileNameFromUri` function into a `getFileName` extension function on the `Uri` class within `common/src/main/java/com/itsaky/androidide/utils/UriExtensions.kt`.
- Updating all call sites to use the new extension function.
- Removing the unused `TOOL` enum value from `ChatMessage.Sender`.
- Simplifying the tool call parsing logic in `LocalLlmRepositoryImpl` by using Kotlinx Serialization instead of manual JSON parsing.

* docs: Add KDoc to buildPromptWithHistory

Add detailed KDoc to the `buildPromptWithHistory` function explaining its purpose and implementation details.

The documentation clarifies that the function currently uses the Llama 3.x chat template and provides guidance on how to adapt it for other model families like Mistral, Gemma, or Phi-3 by modifying the template structure.

* feat: Improve chat message expansion state management

Refactor the expansion state handling for chat messages. Instead of storing the `isExpanded` state within the `ChatMessage` data model, the state is now managed entirely within the `ChatAdapter`.

This change prevents unnecessary recompositions of the entire chat list when a single message's expansion state changes. It introduces a more efficient mechanism using a set of expanded message IDs and `notifyItemChanged` with a specific payload, resulting in smoother UI updates.

* feat(agent): Add localized strings for AI model loading status

Introduces new string resources to provide clearer, localized feedback to the user in the AI settings screen regarding the state of the local model.

This change replaces hardcoded status messages for model loading (idle, loading, loaded, error) with references to the new `strings.xml` entries, improving maintainability and preparing for future internationalization.

* feat(agent): Add localized strings for AI model loading status

Introduces new string resources to provide clearer, localized feedback to the user in the AI settings screen regarding the state of the local model.

This change replaces hardcoded status messages for model loading (idle, loading, loaded, error) with references to the new `strings.xml` entries, improving maintainability and preparing for future internationalization.

* feat(logging): Integrate SLF4J for detailed agent logging

Replaced standard Android `Log` calls with an SLF4J logger in `ChatViewModel` to provide more structured and detailed logging for the AI agent workflow.

Key changes:
- Initialized an SLF4J logger instance.
- Added logs for AI backend initialization, model loading successes and failures, and the start of the agent workflow.
- Included detailed debug logs for agent requests and responses, capturing the prompt, history size, response text, and report.
- Logged significant events like workflow completion time, cancellation by the user, and unexpected errors.
- Removed an unused private function `constructFullPrompt`.

* feat(agent): Add `Cancelling` state for immediate user feedback

Introduces a new `Cancelling` state to the `AgentState` sealed class. This allows the UI to provide immediate feedback when a user requests to stop a generation.

The key changes are:
- A new `AgentState.Cancelling` is added to represent the cancellation request period.
- `ChatViewModel` now sets the state to `Cancelling` at the beginning of `stopAgentResponse()` before the agent and job are actually stopped.
- `ChatFragment` observes this new state and updates the UI accordingly, showing a "Stopping..." message and disabling the "Stop" button to prevent multiple clicks.
- The UI logic for other states (`Idle`, `Processing`, `Error`) has been refined for better consistency and clarity.

* fix(agent): Improve UI state management and agent lifecycle

This commit introduces several improvements to the agent's UI and lifecycle management:

- Prevents sending new messages while the agent is processing, cancelling, or in an error state.
- Disables the send button when the input is empty and re-enables it correctly based on agent state.
- The send button is now hidden and replaced by a "Stop Generation" button during processing, providing a clearer user interface.
- Refactors the `ChatViewModel` to create the AI backend repository only when necessary (e.g., on first use or when settings change), rather than on every message.
- Adds the original user prompt to `sendMessage` to ensure it's displayed correctly, even if a more complex prompt is constructed for the agent.

* Fix: Add reinterpret_cast for AttachCurrentThread

The first argument to `AttachCurrentThread` expects a `void**`, but a `JNIEnv**` was being passed. This change adds the required `reinterpret_cast<void**>` to ensure type correctness and resolve potential compilation issues with newer NDK versions.

* Fix: Use correct AttachCurrentThread signature for C++

The signature for `AttachCurrentThread` differs between C and C++. This change adds an `#ifdef __cplusplus` check to use the correct method signature, ensuring the JNIEnv is properly passed and avoiding compilation errors in C++ mode.

* Fix(llama): Update JNI thread attachment and build scripts

Updates the JNI `AttachCurrentThread` call to use the correct signature for the Android NDK C++ environment, with a fallback for the C signature. This resolves potential build and runtime issues related to thread attachment.

Additionally, this change:
- Replaces the deprecated `llama_new_context_with_model` with `llama_init_from_model`.
- Cleans up comments and adds a missing include directory in `CMakeLists.txt`.

* Fix: Correctly attach JNI thread in C++

The conditional compilation for `AttachCurrentThread` was unnecessary, as the NDK's C++ signature (`JNIEnv**`) is the correct one to use. This change removes the redundant conditional and the fallback C signature.

Additionally, the Android NDK include directory is now prioritized in `CMakeLists.txt` by adding the `BEFORE` keyword to `include_directories`.

* Fix: Correctly attach JNI thread in C++

The conditional compilation for `AttachCurrentThread` was unnecessary, as the NDK's C++ signature (`JNIEnv**`) is the correct one to use. This change removes the redundant conditional and the fallback C signature.

Additionally, the Android NDK include directory is now prioritized in `CMakeLists.txt` by adding the `BEFORE` keyword to `include_directories`.

* feat: Support JNI headers with void** for AttachCurrentThread

Adds a templated `attach_current_thread` wrapper to handle different signatures of `AttachCurrentThread` in JNI headers. This ensures compatibility with headers that use `void**` for the `JNIEnv` argument, such as in the Flox environment, in addition to the standard `JNIEnv**`.

Additionally, this change silences a CMake warning by explicitly setting the `SYSTEM_INCLUDE_DIRECTORIES` property.

* feat(editor): Implement resizable side panel for Agent

This commit introduces a new resizable side panel, primarily for the AI Agent feature, replacing the previous right-side drawer. This improves user experience on tablets and in landscape mode by allowing the user to view and interact with the agent alongside their code.

Key changes:
- Replaced the right `NavigationView` with a `FragmentContainerView` within a `ConstraintLayout` for landscape/tablet layouts.
- Implemented a draggable divider to resize the main content and the new side panel. The panel width can be adjusted between 40% and 90% of the screen.
- For portrait mode, the panel is implemented as a `BottomSheet` that can be toggled.
- A new `AgentPanelController` interface is introduced to abstract the logic for toggling the panel's visibility.
- The left swipe gesture in the editor now toggles this new agent panel instead of opening a right-side drawer.
- The logic for displaying the right sidebar based on experimental flags in `ProjectHandlerActivity` has been removed in favor of this new implementation.

* animate

* refactor(editor): Unify landscape and portrait editor layouts

This commit refactors the editor to use a single `ConstraintLayout`-based layout for both portrait and landscape orientations, removing the separate `layout-port` version.

Key changes:
- Deleted `layout-port/activity_editor.xml`, which used a `CoordinatorLayout` and `BottomSheetBehavior`.
- The unified `activity_editor.xml` now manages the right-side agent panel with a `Guideline`.
- The right panel now starts hidden by default (`guidePercent="1.0"`, `visibility="gone"`).
- Removed the Floating Action Button (FAB) previously used to toggle the agent panel.
- Updated `BaseEditorActivity.kt` to handle the new unified layout logic:
    - Removed logic specific to the old portrait `BottomSheet`.
    - `toggleAgentPanel` now animates the `Guideline` percentage to show or hide the panel.
    - Implemented snapping behavior for the resizable panel: it can snap to a nearly full-screen state or be dismissed if dragged past certain thresholds.

* feat(editor): Set minimum width for editor panel

Introduces a minimum width of 200dp for the editor panel when resizing with the vertical guideline.

The drag gesture now respects this minimum width, preventing the editor from becoming too narrow. When the drag is released, the guideline will snap to hide the right-hand panel if the editor's width is less than the defined minimum, ensuring a better user experience.

* feat(editor): Set minimum width for editor panel

Introduces a minimum width of 200dp for the editor panel when resizing with the vertical guideline.

The drag gesture now respects this minimum width, preventing the editor from becoming too narrow. When the drag is released, the guideline will snap to hide the right-hand panel if the editor's width is less than the defined minimum, ensuring a better user experience.

* Refactor: Change Build Variants sidebar location and remove comment

- The location for the `BuildVariantsSidebarAction` has been updated from `EDITOR_RIGHT_SIDEBAR` to `EDITOR_SIDEBAR`.
- A redundant comment checking the active layout in `BaseEditorActivity` has been removed.

* feat: Relocate sidebar menu items and add plugin build directories to gitignore

The menu gravity in the right editor sidebar has been changed from "bottom" to "top", moving the menu items to the top of the sidebar.

Additionally, build directories for `plugin-api`, and `plugin-manager` have been added to the `.gitignore` file to prevent them from being committed to the repository.

* comments

* refactor(agent): Improve GeminiClient error handling and structure

This commit refactors the `GeminiClient` to improve its structure, error handling, and robustness.

Key changes include:
*   Trimming whitespace from the API key to prevent authentication issues.
*   Introducing a centralized `executeWithRetry` function to handle `ServerException` (5xx errors) with a retry mechanism and to sanitize `ClientException` (4xx errors) by throwing a generic error message. This prevents sensitive information like API keys from being exposed in logs or exceptions.
*   Breaking down the `generateContent` method into smaller, single-responsibility helper functions (`buildGenerateContentConfig`, `executeWithRetry`, `validateResponse`) for better readability and maintenance.
*   The core logic for API calls, including retry attempts for server errors and tool configuration, is now more organized and resilient.

* feat(settings): Improve Gemini API Key management UI

This commit refactors the Gemini API Key settings screen to improve user experience and security.

Key changes include:
- A new UI state that hides the API key input field after a key is saved, showing the save date instead.
- Added "Edit" and "Clear" buttons to allow users to modify or remove their saved key.
- The timestamp of when the API key was saved is now stored and displayed.
- The underlying `EncryptedSharedPreferences` implementation is updated to use the recommended `MasterKeys` builder.

* feat(settings): Improve Gemini API Key management UI

This commit refactors the Gemini API Key settings screen to improve user experience and security.

Key changes include:
- A new UI state that hides the API key input field after a key is saved, showing the save date instead.
- Added "Edit" and "Clear" buttons to allow users to modify or remove their saved key.
- The timestamp of when the API key was saved is now stored and displayed.
- The underlying `EncryptedSharedPreferences` implementation is updated to use the recommended `MasterKeys` builder.

* feat: Use string resources for chat UI

Extract hardcoded strings in the chat fragment and menu to `strings.xml` for localization.

Changes include:
- Use string resources for the chat toolbar title and menu items.
- Update the `ic_add` drawable to use the theme attribute `?attr/colorOnSurfaceVariant` for its fill color, improving theme adaptability.

* refactor: Move AI Agent strings and clean up menus

Move AI-related string resources from the `app` module to the `layouteditor` module to centralize them. This also includes adding new strings for the AI settings UI, such as API key status messages.

Other changes include:
- Refactor the AI settings UI to use the new string resources.
- Clean up the chat menu by removing export, share, and delete options.
- Adjust the size of `chat_history.xml` and `ic_back.xml` drawables.

* env removed

* Fix: Minor cleanups and typo fixes

This commit includes several minor cleanups and corrections:

- Fixes typos in comments within ggml and agent state.
- Removes a period and corrects an ellipsis in string resources.
- Corrects a variable assignment in wasm quantization.
- Fixes a macro name from `GGML_COMPUTE_FP32_TO_FP16` to `GGML_CPU_COMPUTE_FP32_TO_FP16`.
- Removes a trailing semicolon in `LLamaAndroid.kt`.
- Deletes commented-out code explaining how to write GGUF files.

* feat(build): Replace llama module with prebuilt AARs

Removes the `:llama` project module from the build. Instead, introduces `v7` and `v8` implementation configurations that point to prebuilt AAR files (`llama-v7-release.aar` and `llama-v8-release.aar`) located in the `libs/` directory.

This change modularizes the Llama dependency, allowing for different versions to be included as precompiled artifacts rather than source code.

* feat(build): Replace llama module with prebuilt AARs

Removes the `:llama` project module from the build. Instead, introduces `v7` and `v8` implementation configurations that point to prebuilt AAR files (`llama-v7-release.aar` and `llama-v8-release.aar`) located in the `libs/` directory.

This change modularizes the Llama dependency, allowing for different versions to be included as precompiled artifacts rather than source code.

* feat: Bundle architecture-specific Llama AAR into offline zip

This change updates the `createOfflineZip` Gradle task to include the appropriate Llama AAR file based on the target architecture (`arm64-v8a` or `armeabi-v7a`).

The script now:
- Determines the correct AAR file path from `app/libs/`.
- Adds the selected AAR to the offline zip under the generic path `dynamic_libs/llama.aar`.
- Throws an error if the AAR file for the specified architecture is not found.

* feat: Bundle architecture-specific Llama AAR into offline zip

This change updates the `createOfflineZip` Gradle task to include the appropriate Llama AAR file based on the target architecture (`arm64-v8a` or `armeabi-v7a`).

The script now:
- Determines the correct AAR file path from `app/libs/`.
- Adds the selected AAR to the offline zip under the generic path `dynamic_libs/llama.aar`.
- Throws an error if the AAR file for the specified architecture is not found.

* feat: Add support for installing Llama AAR

Adds the logic to install the Llama AAR file from bundled, Brotli-compressed assets. The correct AAR (`llama-v7.aar` for ARM or `llama-v8.aar` for AARCH64) is chosen based on the device's CPU architecture and extracted to the `dynamic_libs` directory.

* feat: Extract llama.aar to dynamic_libs

Extracts the `llama.aar` file from the split assets into the `dynamic_libs` directory within the app's private storage.

* feat: Extract llama.aar to dynamic_libs

Extracts the `llama.aar` file from the split assets into the `dynamic_libs` directory within the app's private storage.

* feat: Add dynamic library loader for Llama AAR

Adds a `DynamicLibraryLoader` utility to dynamically load the `llama.aar` at runtime.

This new loader performs the following steps:
- Locates the `llama.aar` file extracted from assets.
- Unzips the AAR into a versioned directory within the app's `codeCacheDir` to manage updates.
- Creates and returns a `DexClassLoader` configured with the path to `classes.jar` and the appropriate native libraries (`.so` files) for the device's ABI.

* feat: Lazily initialize LLM inference engine

Dynamically load the Llama AAR and initialize the `LlamaAndroid` controller via reflection. This avoids a hard dependency and allows the engine to be initialized on-demand.

The `LlmInferenceEngine` is updated to:
- Add a new `initialize()` method that must be called before using the engine.
- Replace direct calls to the static `LLamaAndroid.instance()` with a nullable `llamaController`.
- Add checks to ensure the engine is initialized before performing operations like loading a model or running inference.

* feat: Remove local llama AAR dependencies

Removes the local AAR file dependencies for `llama-v7-release.aar` and `llama-v8-release.aar`. The implementation configurations `v7Implementation` and `v8Implementation` have been deleted from the `app/build.gradle.kts` file.

* feat: Add llama-api module for abstraction

Introduces a new `llama-api` module to abstract the Llama inference engine implementation. This allows for cleaner separation of concerns and easier future updates.

Changes include:
- Creating the `llama-api` Gradle module.
- Defining an `ILlamaController` interface.
- Updating `LlmInferenceEngine` to use the new interface instead of the concrete implementation.
- Including the new `llama-api` and `llama-impl` modules in the project build.
- Adding necessary dependencies to the new module.

* feat: Bump Java version and update Llama AAR path

- Bumps the Java source and target compatibility from 11 to 17 in the `llama-api` module.
- Updates the AAR filename for the Llama library from `llama-v*-release.aar` to `llama-impl-v*-release.aar`.

* feat: Pre-DEX Llama AAR before packaging into assets

This commit modifies the build process to convert the `classes.jar` inside the Llama AAR to `classes.dex` *before* packaging it into the final `assets-*.zip` file. This is accomplished by using the D8 tool.

Changes include:
- Extracting `classes.jar` from the pre-built `llama-impl-*.aar`.
- Running the `d8` command-line tool to convert the JAR to a DEX file.
- Repackaging the AAR, replacing the original `classes.jar` with the newly generated `classes.dex`.
- Adding `dependsOn` to the `assembleV*Assets` tasks to ensure the Llama AARs are built first.
- In `LlmInferenceEngine`, `initialize()` is now called automatically if needed when loading a model, preventing a potential `Engine not initialized` error.

* feat(llama): Integrate llama.cpp as a native library

This commit integrates `llama.cpp` directly as a native library within the new `llama-impl` module, replacing the previous dynamic AAR loading mechanism.

Key changes:
- Adds a new `llama-impl` Android library module containing the C++ source, JNI bindings, and a `LLamaAndroid.kt` controller.
- Uses CMake to build `llama.cpp` and the JNI wrapper as part of the standard Gradle build process.
- The `createAssetsZip` task in `app/build.gradle.kts` is heavily refactored:
    - It now uses the D8 tool to compile the `llama-impl` module's `classes.jar` and all its dependencies into a `classes.dex` file.
    - The classpath for D8 is correctly constructed by resolving the `llama-impl` module's runtime configuration, ensuring all necessary classes are included.
- Core library desugaring is enabled for Java 17 compatibility.
- ProGuard is enabled for release builds in the `app` module.
- The `DynamicLibraryLoader` is updated to load `classes.dex` instead of `classes.jar`, simplifying the class loading process.

* feat(llama): Integrate llama.cpp as a native library

This commit integrates `llama.cpp` directly as a native library within the new `llama-impl` module, replacing the previous dynamic AAR loading mechanism.

Key changes:
- Adds a new `llama-impl` Android library module containing the C++ source, JNI bindings, and a `LLamaAndroid.kt` controller.
- Uses CMake to build `llama.cpp` and the JNI wrapper as part of the standard Gradle build process.
- The `createAssetsZip` task in `app/build.gradle.kts` is heavily refactored:
    - It now uses the D8 tool to compile the `llama-impl` module's `classes.jar` and all its dependencies into a `classes.dex` file.
    - The classpath for D8 is correctly constructed by resolving the `llama-impl` module's runtime configuration, ensuring all necessary classes are included.
- Core library desugaring is enabled for Java 17 compatibility.
- ProGuard is enabled for release builds in the `app` module.
- The `DynamicLibraryLoader` is updated to load `classes.dex` instead of `classes.jar`, simplifying the class loading process.

* feat: Update dependencies and improve Llama C++ implementation

This commit introduces several updates and fixes:

- Updates the Koin dependency to version 4.1.1 and moves it to the `libs.versions.toml` catalog for centralized version management.
- Removes unused `okhttp` and `kotlinx-serialization-json` dependencies from `app/build.gradle.kts`.
- Implements a more robust memory deallocation for `llama_batch` in the C++ layer to prevent memory leaks.
- Adds an error-handling mechanism in `llama-android.cpp` to throw a `java/lang/IllegalArgumentException` when the prompt size exceeds the model's context size, preventing native crashes.

* feat: Update dependencies and improve Llama C++ implementation

This commit introduces several updates and fixes:

- Updates the Koin dependency to version 4.1.1 and moves it to the `libs.versions.toml` catalog for centralized version management.
- Removes unused `okhttp` and `kotlinx-serialization-json` dependencies from `app/build.gradle.kts`.
- Implements a more robust memory deallocation for `llama_batch` in the C++ layer to prevent memory leaks.
- Adds an error-handling mechanism in `llama-android.cpp` to throw a `java/lang/IllegalArgumentException` when the prompt size exceeds the model's context size, preventing native crashes.

* build: Disable minification for release builds

This commit removes the ProGuard configuration for the `release` build type, effectively disabling code shrinking, obfuscation, and optimization.

The `isMinifyEnabled = true` flag and the `proguardFiles` configuration have been removed from the `release` block in `app/build.gradle.kts`.

* build: Disable minification for release builds

This commit removes the ProGuard configuration for the `release` build type, effectively disabling code shrinking, obfuscation, and optimization.

The `isMinifyEnabled = true` flag and the `proguardFiles` configuration have been removed from the `release` block in `app/build.gradle.kts`.

* refactor(agent): Decouple LlmInferenceEngine from native library and add initialization state

This commit refactors the `LlmInferenceEngine` to decouple it from the static `LLamaAndroid` library. The engine now dynamically loads the native library and its classes at runtime.

**Key Changes:**

-   **Dynamic Library Loading:** `LlmInferenceEngine` no longer directly accesses `LLamaAndroid.instance()`. Instead, it uses a `DynamicLibraryLoader` to get a `ClassLoader` and loads the "android.llama.cpp.LLamaAndroid" class via reflection.
-   **Engine Initialization State:** A new `initialize` method and `EngineState` (`Uninitialized`, `Initializing`, `Initialized`, `Error`) have been introduced. The engine must be successfully initialized before any models can be loaded or inference can be run.
-   **ViewModel and UI Updates:**
    -   `AiSettingsViewModel` now manages the `EngineState` and exposes it via LiveData.
    -   The `AiSettingsFragment` UI observes this state, disabling model selection buttons until the engine is initialized and displaying the current status (e.g., "Initializing engine...", "Engine is ready.").
    -   Model loading is now prevented if the engine is not ready.
-   **Interface-based Control:** The engine now interacts with the loaded llama instance through the `ILlamaController` interface, improving abstraction.
-   **Code Cleanup:** Unused methods and redundant logic in `AiSettingsViewModel` have been removed, and the view model's responsibility is now clearly focused on state management and orchestrating calls to the engine.

* refactor: Move shared string resources to the resources module

The following string resources have been moved from the `app` module to the shared `resources` module to promote reusability and centralize common text:

- `retry`
- `open_ai_settings`
- `new_chat`
- `ai_setting_initializing_engine`
- `ai_setting_engine_ready`

* refactor: Replace getBaseInstance() with baseInstance property access

* fix: support uncompressed llama AAR assets as fallback

- In `BundledAssetsInstaller`, try loading the uncompressed llama AAR asset if the Brotli-compressed version is not found.
- Add Gradle tasks `bundleV7LlamaAssets` and `bundleV8LlamaAssets` to extract `llama.aar` from the assets zip and copy it to the release assets directory.
- In the new Gradle tasks, attempt to compress the AAR with `brotli` if available; otherwise, copy it uncompressed.
- Hook these new bundling tasks into the build process (via `assembleV7Release` and `assembleV8Release`).

* ADFA-2149: Prevent crash when debug events occur before language client initialization (#660)

* feat(ADFA-2097): Do not show chooser when sending feedback email (#670)

* feat(ADFA-2097): Do not show chooser when sending feedback email

* fix(ADFA-2097): Set intent data

* ADFA-2163 | Fix undo enabled state on initial Layout Editor load (#663)

* fix(layout-editor): initialize undo stack correctly
Ensure undo enabled only after first modification

* fix(UndoRedoManager): Use value equality (==) instead of reference equality (===)

* integrate jacoco (#679)

* integrate jacoco for generating a project scope debug unit test coverage report

* clean up comments and commented code

* integrate jacoco for generating a project scope debug unit test coverage report

* clean up comments and commented code

* exclude llama-impl from coverage and bump version of jacoco to 0.8.11

* Improve installer display (#681)

* remove installing status and change FINISHED to green checkmark

* use plain green check instead of with box

* ADFA-2139: Add plugin sidebar slot limiting with manifest declaration and custom IdeNavigationRailView (max 12 items) (#674)

* ADFA-2139: Add plugin sidebar slot limiting with manifest declaration and custom IdeNavigationRailView (max 12 items)

* Fix sidebar slot leak when plugin loading fails after reservation

* ADFA-2139: Add scroll support for nav rail

* ADFA-2167: Fix ConstraintSet crash by ensuring all children have IDs before cloning (#669)

* ADFA-2195: Onboarding flow update (#677)

* feat(ADFA-2195): Add animation to next button

* feat(ADFA-2195): Show privacy dialog on permissions info screen

* refactor(ADFA-2195): Remove unused import

* feat(ADFA-2195): Add animation to finish installation button

* fix(ADFA-2195): Fix typos in function names

* ADFA-2116: reformat strings.xml and exclude it from Spotless formatting (#633)

* fix: formatting errors in strings.xml

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>

* fix: exclude strings.xml from Spotless

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>

* ADFA-2023 | Refactor layout positioning and drop/restore workflow (#606)

* feat(layouteditor): persist widget position on drop; save translationX/Y (dp) and restore on load
fix: clamp within container, add onDrop callback, and avoid re-applying default translation attrs

* refactor: Resolving BOT comments

* refactor: increase decimal places

* refactor: view parent

* refactor(layouteditor): Use ConstraintSet margins for view positioning
Replaces translationX/Y logic with persistent app:layout_marginStart/Top constraints

* FIX: Store and display properly widget positions, must fix jump at drop

* refactor(layout): extract constraint utilities and centralize position restore logic

Moves constraint helpers to ConstraintUtils.kt and integrates restorePositionsAfterLoad across editor and parser. This commit fixes ADFA-1439

* refactor(layout): optimize constraint batching and fix existing view drag-drop

* refactor(layouteditor): extract positioning utils; add drop/restore handlers and fix imports

* feat(LayoutEditor): add support for widgets positioning in GridLayout containers

* fix indent

* refactor(positioning): Optimize view restore to update only the moved view
Introduces `restoreSingleViewPosition` to avoid repositioning all views on drag/drop.

* fix(positioning): Fix indentation

* fix(layouteditor): Use android:layout_margin for universal ViewGroup compatibility

Replaced ConstraintLayout-specific 'app:layout_margin[Start/Top/End/Bottom]' with standard 'android:layout_margin[Start/Top/End/Bottom]' in the positioning logic to resolve build failures in non-ConstraintLayout containers.

* feat(layout-editor): add widget id sanitization for switch
prevent invalid ids by applying override map

* feat(layouteditor): add include marker support and update default widget icons

* fix: re-initialize AttributeInitializer on layout load to update map reference
Prevents writing to stale maps after undo/redo, fixing missing widget attributes

* ADFA-1616 | Improve Gemini API key handling and chat title logic (#684)

* feat: add clearer Gemini API key error message and adjust chat title logic
chore: update UI constraints for multiline tool execution status

* fix(agent): change critic role

* feat(agent): Add "X" mark to the API error message.

* ADFA-2170 | Fix initial TextView positioning behavior (#672)

* fix(layouteditor): ensure initial TextView uses absolute centered position
remove relative constraints and persist correct initial margins

* fix(layouteditor): Add safe calls and remove log

* ADFA-2168:  Fix ViewModel crash in detached fragment by using guarded isEmpty setter (#686)

ADFA-2168: ⏺ Fix ViewModel crash in detached fragment by using guarded isEmpty setter

* Enable StrictMode for debug builds. (#691)

* Enable StrictMode for debug builds.

* Enable StrictMode for debug builds.

* Move enabling of StrictMode to DeviceProtectedApplicationLoader.

* remove unused import and cleanup indentation

* crash the app on all StrictMode violations (#693)

* penaltyLog instead of penaltyDeath in debug builds on presence of feature flag file (#696)

* penaltyLog instead of penaltyDeath in debug builds when the feature flag file CodeOnTheGo.a3s19 is preesent in Download folder

* make file existence check conform to strictmode disk access policy

* rename variable

* ADFA-2128: Handle IllegalArgumentException when previewing NavigationView (#636)

* fix(ADFA-2128): Show error when navigation view is not a child of DrawerLayout

* feat(ADFA-2128): Add support for DrawerLayout in layout editor

* fix(ADFA-2128): Add missing resource

* Minor fixes

* ADFA-2165: Audit layout editor (#673)

* refactor(ADFA-2165): Optimise imports in layouteditor module

* refactor(ADFA-2165): Remove unused activities

* refactor(ADFA-2165): Remove unused files

* Revert "refactor(ADFA-2165): Remove unused files"

This reverts commit 368ef9ff1809fb3d5a6450054857b9d99f13ac9f.

* refactor(ADFA-2165): Remove unused library

---------

Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>

* ADFA-2233 | Fix core-ktx version and re-enable llama-impl in Jacoco (#694)

feat(build): align core-ktx version and re-enable llama-impl for jacoco
Ensures compatibility with current AGP and resolves metadata conflicts

* ADFA-2092: gradle sync error during initialization is incorrectly reported as success (#648)

* fix: initialization failures are incorrectly reported as success
* fix: consider sync file readability when deciding whether to sync
* fix: inverted condition check for areSyncFilesReadable
* fix: missing notifyBuildSuccess call

---------

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>

* ADFA-2248 | Implement created/modified date logic across project components (#689)

* feat: implement created/modified date handling across project adapters
fix: unify date formatting and add lastModified persistence

* refactor: improve created/modified date logic and label consistency
fix: update ordering, labels and rendering

* feat(projects): add DB migration, async file attribute handling, safe calls and fix indentation

* refactor: centralize date rendering and improve project loading UX

* refactor: rename Date.kt to DateFormatter.kt for clearer intent

* ADFA-2230: Fix broken unit test (#690)

* fix(ADFA-2230): Fix broken unit test

* feat(ADFA-2230): Include xml-inflater project

* feat(ADFA-2230): Include previously excluded projects from Jacoco task

* ADFA-2262: Fix compatibility issues (#692)

fix(ADFA-2262): Use a backwards-compatible method

Co-authored-by: Hal Eisen <haleisen@appdevforall.org>

* fix(ADFA-2290): Initialize property before accessing (#704)

* ADFA-2180: Fix ArrayIndexOutOfBoundsException: index = 1, length = 1 on ContentExt.kt (#687)

* ADFA-2224: Fix IllegalStateException: Fragment MainFragment (#682)

* ADFA-2158 Ignore /bin/ directories; ignore IDE directories (#701)

Ignore /bin/ directories; ignore IDE directories

* ADFA-2292 Attempt to extract Jira key from the commit message in debug.yml (#705)

Attempt to extract Jira key from the commit message in debug.yml

* ADFA-1966: Move file operations to background thread (#688)

* fix(ADFA-1966): Move plugin installation file I/Os to background

* fix(ADFA-1966): Move screenshot file I/Os to background

* fix(ADFA-1966): Clean up resources

* fix(ADFA-1966): Clean up temp file in case of exception

* ADFA-2157: Fix tooltip crash when activity is destroyed or view detached (#664)

* ADFA-2157: Fix tooltip crash when activity is destroyed or view detached

* return false for activityValid check

* ADFA-2284 Push the 4am nightly build to a directory on the website (#711)

* upload apks to greengeeks apk_repo folder

* disable notification for test runs

* disable distribution to firebase for test

* finalize and clean out test scaffolding

* make variable names clearer and cleanup ssh key and hosts

* remove unnecessary code

---------

Co-authored-by: Hal Eisen <haleisen@appdevforall.org>

* ADFA-2206: Fix NPE in asset installation when zip entry is missing (#699)

* ADFA-2206: Fix NPE in asset installation when zip entry is missing

* ADFA-2206: Display specific error message in flash message

* ADFA-2206: Display specific error message in flash message

* ADFA-2206: Display specific error message in flash message

* ADFA-2312: Fix StringIndexOutOfBoundsException in DimensionUtil.getDimenWithoutSuffix (#714)

Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>

* ADFA-2264 automate adding fix version YY.ww to Jira ticket on merge to stage (#715)

* ADFA-2264 automate adding fix version YY.ww to Jira ticket on merge to stage

* More secure and accurate head refs in .github/workflows/debug.yml

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Addresses CodeRabbit's suggestion for more clear handling of NEXT_RELEASE_VERSION

* Fix jq install location

* Move initialization of NEXT_RELEASE_VERSION

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* ADFA-2247 | Add search, sorting, and filtering UI for saved projects (#700)

* feat(ui): add search bar and sort controls to saved projects screen
feat: include new icons and string resources for sorting options

* feat(projects): implement search and sorting via new filter sheet
Refactor UI and ViewModel to support dynamic filtering and updated layouts

* feat(projects): add Doc Strings, changing btn background and text and change direction btn design

* feat(projects): remove commented line and added a todo

* refactor: remove the unimplemented `date modified` filter and add comments to add it later.

* refactor: add `date modified` filter to recent projects page

* fix(recent_projects): Replace delay with events and native debounce

* refactor(sorting): Use data class instead of Triple

* refactor(recent_projects): Refactoring UI: everything related to “filtering” was removed, since we are only sorting. Replaced icons with Material icons

* refactor(recent-projects): Make `applyFilters` run on the CPU thread

* feat(recent-projects): Add string for screen reader users

* refactor(recent-projects): Using `requireViewById` instead of `findViewById`

* ADFA-2264 Attempt to fix broken build by looking for Jira ticket key in more places (#720)

* ADFA-2264 Attempt to fix broken build by looking for Jira ticket key in more places

* Simplify grep looking for ticket key

* ADFA-2323-Change-caps-in-Developer-options-pref (#722)

Correct string casing for 'Developer Options'

* fix(ADFA-2280): Display search results on first search (#712)

* fix(ADFA-2280): Display search results on first search

* fix(ADFA-2280): Rework solution

* refactor(ADFA-2280): Remove redundant adapter setting

---------

Co-authored-by: Hal Eisen <haleisen@appdevforall.org>
Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>

* ADFA-1304 | Add Project Info Bottom Sheet (#706)

* feat: add full project info bottom sheet with details and DB migration
includes UI, tooltips, parser utils, and RecentProjects integration

* refactor(project_info): Remove duplicated code, remove unused imports, fix indentation and added KDocs to InfoRowView.kt

* fix(recent_projects): Fix indentation

* refactor(project-info): enforce I/O safety and simplify InfoRowView usage

- Make build version utility functions `suspend` and `Main-Safe` using `Dispatchers.IO` to comply with StrictMode.
- Add `setLabelAndValue` helper to `InfoRowView` and update `ProjectInfoBottomSheet` to reduce boilerplate.
- Remove redundant XML comments.

* refactor(project-info): Improve the loading time of project information

* refactor(projects_info): Improve UI/UX for close button

* feat: improve Kotlin version detection in project details

Enhances readKotlinVersion to read versions from app Gradle files and libs.versions.toml when root directory is passed

* refactor: Improve Kotlin detection for project info panel

* resolve merge conflicts

---------

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>
Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>
Co-authored-by: Daniel-ADFA <danielalome@appdevforall.org>
Co-authored-by: Dara Abijo <oluwadara.abijo@appdevforall.org>
Co-authored-by: jomen-adfa <joelmenchavez@appdevforall.org>
Co-authored-by: itsaky-adfa <akashyadav@appdevforall.org>
Co-authored-by: Hal Eisen <haleisen@appdevforall.org>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Elissa-AppDevforAll <elissamiller@appdevforall.org>
avestaadfa added a commit that referenced this pull request Jan 7, 2026
* wip: Implement computer vision experimental.

* Fix build.gradle.kts for cv-image-xml structure

* Add back navigation and Update button to write generated XML back to source layout file

* wip: refactor CV experimental

* Chore adfa 1552 (#736)

* ADFA-2164 | Prevent crash when loading invalid font files (#650)

* fix: prevent crash when loading invalid font files
Add validation and UI warnings for empty or corrupt font files.

* refactor(layouteditor): Change threads handling, add magic constants and Log exception

* refactor(layouteditor): Address bot comments, first valid then copy file, initialize executor and shutdown in onDestroyView

* fix(fonts): validate before copy and avoid broken UI entries

* refactor(strings): add a descriptive error message

* Implement On-Demand Loading for Llama Module from Assets (#491)

* feat: Integrate llama.cpp as a new module

This commit introduces a new `:llama` Android library module that integrates the `llama.cpp` library for local large language model inference.

The module provides a `LLamaAndroid` Kotlin class, which acts as a singleton wrapper around the native `llama.cpp` functions via JNI. This enables loading models, managing contexts, tokenizing text, and running inference.

Key changes:
- **Module Creation:** Added a new `:llama` library module with its own Gradle build files (`build.gradle.kts`), ProGuard rules, and Android Manifest.
- **Native Integration:**
    - Included a `CMakeLists.txt` to build `llama.cpp` from a local source directory.
    - Added `llama-android.cpp` which contains the JNI bridge between Kotlin and the native C++ functions.
    - Implemented native functions for model/context/batch/sampler management, tokenization, inference (`completion_init`, `completion_loop`), and benchmarking.
    - Configured `llama_log_set` to redirect native logs to Android's Logcat.
- **Kotlin Wrapper (`LLamaAndroid.kt`):**
    - Created a singleton `LLamaAndroid` class to manage the lifecycle of the native llama.cpp objects.
    - Exposed high-level functions like `load()`, `unload()`, `send()`, `tokenize()`, and `bench()`.
    - Manages native state on a dedicated single-threaded coroutine dispatcher to ensure thread safety.
- **Build Configuration:**
    - Added `:llama` as a dependency to the main `:app` module and included it in `settings.gradle.kts`.
    - Configured CMake arguments in `llama/build.gradle.kts` to customize the `llama.cpp` build (e.g., disabling CURL).
- **Bug Fixes & Improvements:**
    - Increased the `n_batch` size to 2048 in `LLamaAndroid.kt` to prevent failures with larger contexts.
    - Corrected the implementation of the `tokenize` JNI function to use the `common_tokenize` helper, ensuring consistency.
    - Added a repetition penalty sampler to the default sampler chain in the C++ code to improve text generation quality.

* refactor: Use relative path for llama.cpp submodule

This commit updates the `CMakeLists.txt` file to use a relative path instead of a hardcoded absolute path for the `llama.cpp` dependency.

This change makes the build process portable and independent of the local user's directory structure. The `llama.cpp` source is now expected to be located in `subprojects/llama.cpp/`.

* refactor: Use relative path for llama.cpp submodule

This commit updates the `CMakeLists.txt` file to use a relative path instead of a hardcoded absolute path for the `llama.cpp` dependency.

This change makes the build process portable and independent of the local user's directory structure. The `llama.cpp` source is now expected to be located in `subprojects/llama.cpp/`.

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* Unnecessary files removed

* COmments

* COmments

* working

* refactor

* refactor(agent): Improve Local LLM Repository and agentic loop

This commit refactors the local LLM implementation by moving the inference logic into a dedicated `LlmInferenceEngine` object within the `repository` package.

Key changes:
- **New `LlmInferenceEngine`:** A new singleton object in the `agent.repository` package now manages the `LLamaAndroid` instance, including model loading, unloading, and inference. This replaces the deleted `LlmInterfaceEngine` from the `app` package.
- **Improved Agentic Loop:** The agentic loop in `LocalLlmRepositoryImpl` is now more robust. It correctly formats history for the model, adds the model's raw response to the history for better context, and continues the loop when tool call parsing fails.
- **Refined System Prompt:** The system prompt is clearer, instructing the model to use `[TOOL_CALL]` markers and providing a better example. Tool definitions are also formatted more cleanly.
- **`generateCode` Implementation:** Implemented the `generateCode` function to allow code generation with the local LLM.
- **Lenient JSON Parsing:** The JSON parser is now configured to be lenient to better handle malformed JSON output from the model.

* feat(agent): Add support for local LLM backend

This change introduces a switchable backend system for the AI Agent, allowing users to choose between the existing Gemini API and a new local LLM backend.

The `ChatViewModel` has been refactored to initialize the appropriate AI repository (`AgenticRunner` for Gemini or `LocalLlmRepositoryImpl` for local models) on-demand when a message is sent. This removes the previous one-time initialization logic and allows the backend to be switched dynamically.

The `AiSettingsFragment` is updated to:
- Allow users to select their preferred AI backend (Gemini or Local LLM).
- Provide a file picker for users to select a local model file when the Local LLM backend is chosen.
- The UI now dynamically shows settings relevant to the selected backend.

* binding

* binding

* loading

* Model loaded successfully

* info from settings

* feat(ai): Synchronize model loading state between UI and engine

This commit refactors the local AI model loading logic to ensure the UI state (`AiSettingsViewModel`) is always synchronized with the underlying inference engine (`LlmInferenceEngine`).

Key changes:
- `LlmInferenceEngine` now tracks the loaded model's name and status.
- The `getFileNameFromUri` helper function is moved into `LlmInferenceEngine` to keep state management self-contained.
- `AiSettingsViewModel` now checks the engine's status on startup (`checkInitialSavedModel`) to correctly reflect an already-loaded model in the UI, preventing the need for the user to reload it.
- Model loading in the ViewModel is simplified to directly sync its state from the engine after a load attempt.

* feat(agent): Add backend status indicator to chat screen

This commit introduces a UI element on the chat screen to display the currently active AI backend (e.g., Gemini or a local model's filename). This replaces the previous "Agent Mode" dropdown menu.

Key changes:
- Adds a backend status view in `fragment_chat.xml` which includes an icon and text to show the current AI backend.
- Removes the now-unused "Agent Mode" dropdown menu.
- In `ChatViewModel`, logic is added to format and expose the backend display text via `LiveData`.
- The view model now updates this status display continuously when the fragment is resumed, in addition to showing a one-time system message when the backend is changed.

* feat(agent): Implement cooperative cancellation for agent tasks

This change introduces a robust mechanism to stop ongoing AI agent tasks, including local LLM inference and agentic workflows.

Key changes:
- A `stop()` method has been added to the `GeminiRepository` interface and implemented across all relevant repositories (`LocalLlmRepositoryImpl`, `AgenticRunner`, `SwitchableGeminiRepository`).
- The native `LLamaAndroid` class now includes a `stop()` method that sets an atomic flag, allowing the inference loop to terminate cooperatively.
- `AgenticRunner` now uses a cancellable `CoroutineScope` to manage its lifecycle, allowing its execution loop to be interrupted.
- `ChatViewModel`'s `stopAgentResponse()` method now calls both `agentRepository.stop()` and cancels the coroutine job to ensure a fast and clean shutdown of the agent task.
- Error handling in `ChatViewModel` is improved to manage cancellations gracefully and reset the agent's state.

* feat(agent): Implement cooperative cancellation for agent tasks

This change introduces a robust mechanism to stop ongoing AI agent tasks, including local LLM inference and agentic workflows.

Key changes:
- A `stop()` method has been added to the `GeminiRepository` interface and implemented across all relevant repositories (`LocalLlmRepositoryImpl`, `AgenticRunner`, `SwitchableGeminiRepository`).
- The native `LLamaAndroid` class now includes a `stop()` method that sets an atomic flag, allowing the inference loop to terminate cooperatively.
- `AgenticRunner` now uses a cancellable `CoroutineScope` to manage its lifecycle, allowing its execution loop to be interrupted.
- `ChatViewModel`'s `stopAgentResponse()` method now calls both `agentRepository.stop()` and cancels the coroutine job to ensure a fast and clean shutdown of the agent task.
- Error handling in `ChatViewModel` is improved to manage cancellations gracefully and reset the agent's state.

* Refactor(agent): Improve local LLM agentic loop and tool handling

This commit introduces several key improvements to the local Large Language Model (LLM) agent:

-   **Refactors Tool Execution**: The `Tool.execute` method's argument type is changed from `Map<String, Any>` to `Map<String, JsonElement>` for better type safety and consistency with JSON parsing.
-   **Improves Agentic Loop**: The agentic loop in `LocalLlmRepositoryImpl` is significantly enhanced. It now builds a more structured prompt history, manages conversation state, and uses stop strings to better control model output and detect the end of tool calls.
-   **Enhances Tool Parsing**: A new `parseToolCall` function replaces the previous regex-based approach. It now uses `JSONObject` for more robust parsing of `<tool_call>` blocks from the model's output.
-   **Removes Unused Code**: The `SwitchableGeminiRepository` class, which was responsible for switching between different AI backends, has been entirely removed as it is no longer in use. Cleaned up comments in `AgenticRunner`.
-   **Adds Stop String to Inference**: The `LlmInferenceEngine.runInference` method now accepts a list of stop strings, allowing more fine-grained control over the generation process.

* feat(agent): Show intermediate progress for local LLM and Gemini

This change introduces an `onProgressUpdate` callback to show intermediate steps from the AI agent in the chat UI.

The `GeminiRepository` and `AgenticRunner` interfaces now include the optional `onProgressUpdate` callback.

In `ChatViewModel`, this callback is implemented for both `AgenticRunner` and `LocalLlmRepositoryImpl` to add progress messages directly to the current chat session.

The `LocalLlmRepositoryImpl` has been refactored to leverage this new callback. It now sends back "thought" processes, tool calls, and tool results as system messages during its agentic loop. This removes the need for the repository to manage its own internal UI message list, simplifying its logic and providing real-time updates to the user.

* feat(agent): Add timers to track agent operation duration

This commit introduces timers to measure and display the total and step-by-step duration of AI agent operations.

- A new `onStateUpdate` callback is added to the agent repositories (`AgenticRunner`, `LocalLlmRepositoryImpl`) to listen for state changes.
- The `ChatViewModel` now starts a timer when an agent operation begins and stops it upon completion.
- A `resetStepTimer()` function is called whenever the agent enters a new `Processing` state, allowing for tracking the duration of individual steps.

* feat(agent): Add timers to track agent operation duration

This commit introduces timers to measure and display the total and step-by-step duration of AI agent operations.

- A new `onStateUpdate` callback is added to the agent repositories (`AgenticRunner`, `LocalLlmRepositoryImpl`) to listen for state changes.
- The `ChatViewModel` now starts a timer when an agent operation begins and stops it upon completion.
- A `resetStepTimer()` function is called whenever the agent enters a new `Processing` state, allowing for tracking the duration of individual steps.

* feat(chat): Replace placeholder message with new message

Instead of updating the "thinking..." placeholder message with the agent's response, remove the placeholder and add the agent's response as a new message. This ensures the new message appears at the bottom of the chat, improving the user experience.

* feat(agent): Add collapsible system messages

This commit introduces a separate, collapsible view type for system and tool messages in the agent chat.

Key changes:
- Created a new `list_item_chat_system_message.xml` layout for system messages, featuring an expandable/collapsible header.
- Added new icons (`ic_robot`, `ic_expand_more`) for the system message view.
- Modified `ChatAdapter` to support multiple view types (`VIEW_TYPE_DEFAULT` and `VIEW_TYPE_SYSTEM`).
- Implemented `SystemMessageViewHolder` to handle the binding and expand/collapse logic for system messages.
- Added an `isExpanded` state to the `ChatMessage` data class to manage the visibility of system message content.
- Updated `DiffCallback` to ensure smooth animations when the `isExpanded` state changes.

* feat(agent): Add collapsible system messages

This commit introduces a separate, collapsible view type for system and tool messages in the agent chat.

Key changes:
- Created a new `list_item_chat_system_message.xml` layout for system messages, featuring an expandable/collapsible header.
- Added new icons (`ic_robot`, `ic_expand_more`) for the system message view.
- Modified `ChatAdapter` to support multiple view types (`VIEW_TYPE_DEFAULT` and `VIEW_TYPE_SYSTEM`).
- Implemented `SystemMessageViewHolder` to handle the binding and expand/collapse logic for system messages.
- Added an `isExpanded` state to the `ChatMessage` data class to manage the visibility of system message content.
- Updated `DiffCallback` to ensure smooth animations when the `isExpanded` state changes.

* feat: Show preview for collapsed system logs

Adds a single-line preview for collapsed system log messages in the chat. This provides users with context about the log's content without needing to expand it.

When collapsed, the system message header now displays "Log: " followed by a cleaned-up, single-line version of the markdown content. When expanded, it reverts to the simple "System Log" title.

* feat(logging): Replace Android Log with SLF4J

Replaces the Android `Log` utility with SLF4J for structured and more robust logging across the `llama` and `app` modules.

This change introduces the SLF4J dependency and refactors the logging calls in `LLamaAndroid` and `LlmInferenceEngine` to use the new framework. This improves logging consistency and removes unnecessary comments and KDoc.

* feat: Bridge native llama.cpp logs to slf4j

Introduces a JNI bridge to forward logs from the native `llama.cpp` layer to the Kotlin/Java side, utilizing the slf4j logging framework.

This change replaces the direct `__android_log_print` calls with a more robust logging mechanism. It correctly handles JNI thread attachment and detachment to prevent crashes, ensuring that native logs are properly surfaced within the Android application's logging system.

* feat: Add specific C++ to Kotlin info logging

Introduces a new C++ function `log_info_to_kt` to send formatted `INFO` level logs directly to the Kotlin bridge. This is used to replace a general `LOGi` call for more specific logging of token caching details.

The `LLamaAndroid.kt` file is also cleaned up by removing a redundant comment.

* Refactor: Move `getFileNameFromUri` to Uri extension and remove unused code

This commit refactors the codebase by:
- Moving the duplicated `getFileNameFromUri` function into a `getFileName` extension function on the `Uri` class within `common/src/main/java/com/itsaky/androidide/utils/UriExtensions.kt`.
- Updating all call sites to use the new extension function.
- Removing the unused `TOOL` enum value from `ChatMessage.Sender`.
- Simplifying the tool call parsing logic in `LocalLlmRepositoryImpl` by using Kotlinx Serialization instead of manual JSON parsing.

* Refactor: Move `getFileNameFromUri` to Uri extension and remove unused code

This commit refactors the codebase by:
- Moving the duplicated `getFileNameFromUri` function into a `getFileName` extension function on the `Uri` class within `common/src/main/java/com/itsaky/androidide/utils/UriExtensions.kt`.
- Updating all call sites to use the new extension function.
- Removing the unused `TOOL` enum value from `ChatMessage.Sender`.
- Simplifying the tool call parsing logic in `LocalLlmRepositoryImpl` by using Kotlinx Serialization instead of manual JSON parsing.

* docs: Add KDoc to buildPromptWithHistory

Add detailed KDoc to the `buildPromptWithHistory` function explaining its purpose and implementation details.

The documentation clarifies that the function currently uses the Llama 3.x chat template and provides guidance on how to adapt it for other model families like Mistral, Gemma, or Phi-3 by modifying the template structure.

* feat: Improve chat message expansion state management

Refactor the expansion state handling for chat messages. Instead of storing the `isExpanded` state within the `ChatMessage` data model, the state is now managed entirely within the `ChatAdapter`.

This change prevents unnecessary recompositions of the entire chat list when a single message's expansion state changes. It introduces a more efficient mechanism using a set of expanded message IDs and `notifyItemChanged` with a specific payload, resulting in smoother UI updates.

* feat(agent): Add localized strings for AI model loading status

Introduces new string resources to provide clearer, localized feedback to the user in the AI settings screen regarding the state of the local model.

This change replaces hardcoded status messages for model loading (idle, loading, loaded, error) with references to the new `strings.xml` entries, improving maintainability and preparing for future internationalization.

* feat(agent): Add localized strings for AI model loading status

Introduces new string resources to provide clearer, localized feedback to the user in the AI settings screen regarding the state of the local model.

This change replaces hardcoded status messages for model loading (idle, loading, loaded, error) with references to the new `strings.xml` entries, improving maintainability and preparing for future internationalization.

* feat(logging): Integrate SLF4J for detailed agent logging

Replaced standard Android `Log` calls with an SLF4J logger in `ChatViewModel` to provide more structured and detailed logging for the AI agent workflow.

Key changes:
- Initialized an SLF4J logger instance.
- Added logs for AI backend initialization, model loading successes and failures, and the start of the agent workflow.
- Included detailed debug logs for agent requests and responses, capturing the prompt, history size, response text, and report.
- Logged significant events like workflow completion time, cancellation by the user, and unexpected errors.
- Removed an unused private function `constructFullPrompt`.

* feat(agent): Add `Cancelling` state for immediate user feedback

Introduces a new `Cancelling` state to the `AgentState` sealed class. This allows the UI to provide immediate feedback when a user requests to stop a generation.

The key changes are:
- A new `AgentState.Cancelling` is added to represent the cancellation request period.
- `ChatViewModel` now sets the state to `Cancelling` at the beginning of `stopAgentResponse()` before the agent and job are actually stopped.
- `ChatFragment` observes this new state and updates the UI accordingly, showing a "Stopping..." message and disabling the "Stop" button to prevent multiple clicks.
- The UI logic for other states (`Idle`, `Processing`, `Error`) has been refined for better consistency and clarity.

* fix(agent): Improve UI state management and agent lifecycle

This commit introduces several improvements to the agent's UI and lifecycle management:

- Prevents sending new messages while the agent is processing, cancelling, or in an error state.
- Disables the send button when the input is empty and re-enables it correctly based on agent state.
- The send button is now hidden and replaced by a "Stop Generation" button during processing, providing a clearer user interface.
- Refactors the `ChatViewModel` to create the AI backend repository only when necessary (e.g., on first use or when settings change), rather than on every message.
- Adds the original user prompt to `sendMessage` to ensure it's displayed correctly, even if a more complex prompt is constructed for the agent.

* Fix: Add reinterpret_cast for AttachCurrentThread

The first argument to `AttachCurrentThread` expects a `void**`, but a `JNIEnv**` was being passed. This change adds the required `reinterpret_cast<void**>` to ensure type correctness and resolve potential compilation issues with newer NDK versions.

* Fix: Use correct AttachCurrentThread signature for C++

The signature for `AttachCurrentThread` differs between C and C++. This change adds an `#ifdef __cplusplus` check to use the correct method signature, ensuring the JNIEnv is properly passed and avoiding compilation errors in C++ mode.

* Fix(llama): Update JNI thread attachment and build scripts

Updates the JNI `AttachCurrentThread` call to use the correct signature for the Android NDK C++ environment, with a fallback for the C signature. This resolves potential build and runtime issues related to thread attachment.

Additionally, this change:
- Replaces the deprecated `llama_new_context_with_model` with `llama_init_from_model`.
- Cleans up comments and adds a missing include directory in `CMakeLists.txt`.

* Fix: Correctly attach JNI thread in C++

The conditional compilation for `AttachCurrentThread` was unnecessary, as the NDK's C++ signature (`JNIEnv**`) is the correct one to use. This change removes the redundant conditional and the fallback C signature.

Additionally, the Android NDK include directory is now prioritized in `CMakeLists.txt` by adding the `BEFORE` keyword to `include_directories`.

* Fix: Correctly attach JNI thread in C++

The conditional compilation for `AttachCurrentThread` was unnecessary, as the NDK's C++ signature (`JNIEnv**`) is the correct one to use. This change removes the redundant conditional and the fallback C signature.

Additionally, the Android NDK include directory is now prioritized in `CMakeLists.txt` by adding the `BEFORE` keyword to `include_directories`.

* feat: Support JNI headers with void** for AttachCurrentThread

Adds a templated `attach_current_thread` wrapper to handle different signatures of `AttachCurrentThread` in JNI headers. This ensures compatibility with headers that use `void**` for the `JNIEnv` argument, such as in the Flox environment, in addition to the standard `JNIEnv**`.

Additionally, this change silences a CMake warning by explicitly setting the `SYSTEM_INCLUDE_DIRECTORIES` property.

* feat(editor): Implement resizable side panel for Agent

This commit introduces a new resizable side panel, primarily for the AI Agent feature, replacing the previous right-side drawer. This improves user experience on tablets and in landscape mode by allowing the user to view and interact with the agent alongside their code.

Key changes:
- Replaced the right `NavigationView` with a `FragmentContainerView` within a `ConstraintLayout` for landscape/tablet layouts.
- Implemented a draggable divider to resize the main content and the new side panel. The panel width can be adjusted between 40% and 90% of the screen.
- For portrait mode, the panel is implemented as a `BottomSheet` that can be toggled.
- A new `AgentPanelController` interface is introduced to abstract the logic for toggling the panel's visibility.
- The left swipe gesture in the editor now toggles this new agent panel instead of opening a right-side drawer.
- The logic for displaying the right sidebar based on experimental flags in `ProjectHandlerActivity` has been removed in favor of this new implementation.

* animate

* refactor(editor): Unify landscape and portrait editor layouts

This commit refactors the editor to use a single `ConstraintLayout`-based layout for both portrait and landscape orientations, removing the separate `layout-port` version.

Key changes:
- Deleted `layout-port/activity_editor.xml`, which used a `CoordinatorLayout` and `BottomSheetBehavior`.
- The unified `activity_editor.xml` now manages the right-side agent panel with a `Guideline`.
- The right panel now starts hidden by default (`guidePercent="1.0"`, `visibility="gone"`).
- Removed the Floating Action Button (FAB) previously used to toggle the agent panel.
- Updated `BaseEditorActivity.kt` to handle the new unified layout logic:
    - Removed logic specific to the old portrait `BottomSheet`.
    - `toggleAgentPanel` now animates the `Guideline` percentage to show or hide the panel.
    - Implemented snapping behavior for the resizable panel: it can snap to a nearly full-screen state or be dismissed if dragged past certain thresholds.

* feat(editor): Set minimum width for editor panel

Introduces a minimum width of 200dp for the editor panel when resizing with the vertical guideline.

The drag gesture now respects this minimum width, preventing the editor from becoming too narrow. When the drag is released, the guideline will snap to hide the right-hand panel if the editor's width is less than the defined minimum, ensuring a better user experience.

* feat(editor): Set minimum width for editor panel

Introduces a minimum width of 200dp for the editor panel when resizing with the vertical guideline.

The drag gesture now respects this minimum width, preventing the editor from becoming too narrow. When the drag is released, the guideline will snap to hide the right-hand panel if the editor's width is less than the defined minimum, ensuring a better user experience.

* Refactor: Change Build Variants sidebar location and remove comment

- The location for the `BuildVariantsSidebarAction` has been updated from `EDITOR_RIGHT_SIDEBAR` to `EDITOR_SIDEBAR`.
- A redundant comment checking the active layout in `BaseEditorActivity` has been removed.

* feat: Relocate sidebar menu items and add plugin build directories to gitignore

The menu gravity in the right editor sidebar has been changed from "bottom" to "top", moving the menu items to the top of the sidebar.

Additionally, build directories for `plugin-api`, and `plugin-manager` have been added to the `.gitignore` file to prevent them from being committed to the repository.

* comments

* refactor(agent): Improve GeminiClient error handling and structure

This commit refactors the `GeminiClient` to improve its structure, error handling, and robustness.

Key changes include:
*   Trimming whitespace from the API key to prevent authentication issues.
*   Introducing a centralized `executeWithRetry` function to handle `ServerException` (5xx errors) with a retry mechanism and to sanitize `ClientException` (4xx errors) by throwing a generic error message. This prevents sensitive information like API keys from being exposed in logs or exceptions.
*   Breaking down the `generateContent` method into smaller, single-responsibility helper functions (`buildGenerateContentConfig`, `executeWithRetry`, `validateResponse`) for better readability and maintenance.
*   The core logic for API calls, including retry attempts for server errors and tool configuration, is now more organized and resilient.

* feat(settings): Improve Gemini API Key management UI

This commit refactors the Gemini API Key settings screen to improve user experience and security.

Key changes include:
- A new UI state that hides the API key input field after a key is saved, showing the save date instead.
- Added "Edit" and "Clear" buttons to allow users to modify or remove their saved key.
- The timestamp of when the API key was saved is now stored and displayed.
- The underlying `EncryptedSharedPreferences` implementation is updated to use the recommended `MasterKeys` builder.

* feat(settings): Improve Gemini API Key management UI

This commit refactors the Gemini API Key settings screen to improve user experience and security.

Key changes include:
- A new UI state that hides the API key input field after a key is saved, showing the save date instead.
- Added "Edit" and "Clear" buttons to allow users to modify or remove their saved key.
- The timestamp of when the API key was saved is now stored and displayed.
- The underlying `EncryptedSharedPreferences` implementation is updated to use the recommended `MasterKeys` builder.

* feat: Use string resources for chat UI

Extract hardcoded strings in the chat fragment and menu to `strings.xml` for localization.

Changes include:
- Use string resources for the chat toolbar title and menu items.
- Update the `ic_add` drawable to use the theme attribute `?attr/colorOnSurfaceVariant` for its fill color, improving theme adaptability.

* refactor: Move AI Agent strings and clean up menus

Move AI-related string resources from the `app` module to the `layouteditor` module to centralize them. This also includes adding new strings for the AI settings UI, such as API key status messages.

Other changes include:
- Refactor the AI settings UI to use the new string resources.
- Clean up the chat menu by removing export, share, and delete options.
- Adjust the size of `chat_history.xml` and `ic_back.xml` drawables.

* env removed

* Fix: Minor cleanups and typo fixes

This commit includes several minor cleanups and corrections:

- Fixes typos in comments within ggml and agent state.
- Removes a period and corrects an ellipsis in string resources.
- Corrects a variable assignment in wasm quantization.
- Fixes a macro name from `GGML_COMPUTE_FP32_TO_FP16` to `GGML_CPU_COMPUTE_FP32_TO_FP16`.
- Removes a trailing semicolon in `LLamaAndroid.kt`.
- Deletes commented-out code explaining how to write GGUF files.

* feat(build): Replace llama module with prebuilt AARs

Removes the `:llama` project module from the build. Instead, introduces `v7` and `v8` implementation configurations that point to prebuilt AAR files (`llama-v7-release.aar` and `llama-v8-release.aar`) located in the `libs/` directory.

This change modularizes the Llama dependency, allowing for different versions to be included as precompiled artifacts rather than source code.

* feat(build): Replace llama module with prebuilt AARs

Removes the `:llama` project module from the build. Instead, introduces `v7` and `v8` implementation configurations that point to prebuilt AAR files (`llama-v7-release.aar` and `llama-v8-release.aar`) located in the `libs/` directory.

This change modularizes the Llama dependency, allowing for different versions to be included as precompiled artifacts rather than source code.

* feat: Bundle architecture-specific Llama AAR into offline zip

This change updates the `createOfflineZip` Gradle task to include the appropriate Llama AAR file based on the target architecture (`arm64-v8a` or `armeabi-v7a`).

The script now:
- Determines the correct AAR file path from `app/libs/`.
- Adds the selected AAR to the offline zip under the generic path `dynamic_libs/llama.aar`.
- Throws an error if the AAR file for the specified architecture is not found.

* feat: Bundle architecture-specific Llama AAR into offline zip

This change updates the `createOfflineZip` Gradle task to include the appropriate Llama AAR file based on the target architecture (`arm64-v8a` or `armeabi-v7a`).

The script now:
- Determines the correct AAR file path from `app/libs/`.
- Adds the selected AAR to the offline zip under the generic path `dynamic_libs/llama.aar`.
- Throws an error if the AAR file for the specified architecture is not found.

* feat: Add support for installing Llama AAR

Adds the logic to install the Llama AAR file from bundled, Brotli-compressed assets. The correct AAR (`llama-v7.aar` for ARM or `llama-v8.aar` for AARCH64) is chosen based on the device's CPU architecture and extracted to the `dynamic_libs` directory.

* feat: Extract llama.aar to dynamic_libs

Extracts the `llama.aar` file from the split assets into the `dynamic_libs` directory within the app's private storage.

* feat: Extract llama.aar to dynamic_libs

Extracts the `llama.aar` file from the split assets into the `dynamic_libs` directory within the app's private storage.

* feat: Add dynamic library loader for Llama AAR

Adds a `DynamicLibraryLoader` utility to dynamically load the `llama.aar` at runtime.

This new loader performs the following steps:
- Locates the `llama.aar` file extracted from assets.
- Unzips the AAR into a versioned directory within the app's `codeCacheDir` to manage updates.
- Creates and returns a `DexClassLoader` configured with the path to `classes.jar` and the appropriate native libraries (`.so` files) for the device's ABI.

* feat: Lazily initialize LLM inference engine

Dynamically load the Llama AAR and initialize the `LlamaAndroid` controller via reflection. This avoids a hard dependency and allows the engine to be initialized on-demand.

The `LlmInferenceEngine` is updated to:
- Add a new `initialize()` method that must be called before using the engine.
- Replace direct calls to the static `LLamaAndroid.instance()` with a nullable `llamaController`.
- Add checks to ensure the engine is initialized before performing operations like loading a model or running inference.

* feat: Remove local llama AAR dependencies

Removes the local AAR file dependencies for `llama-v7-release.aar` and `llama-v8-release.aar`. The implementation configurations `v7Implementation` and `v8Implementation` have been deleted from the `app/build.gradle.kts` file.

* feat: Add llama-api module for abstraction

Introduces a new `llama-api` module to abstract the Llama inference engine implementation. This allows for cleaner separation of concerns and easier future updates.

Changes include:
- Creating the `llama-api` Gradle module.
- Defining an `ILlamaController` interface.
- Updating `LlmInferenceEngine` to use the new interface instead of the concrete implementation.
- Including the new `llama-api` and `llama-impl` modules in the project build.
- Adding necessary dependencies to the new module.

* feat: Bump Java version and update Llama AAR path

- Bumps the Java source and target compatibility from 11 to 17 in the `llama-api` module.
- Updates the AAR filename for the Llama library from `llama-v*-release.aar` to `llama-impl-v*-release.aar`.

* feat: Pre-DEX Llama AAR before packaging into assets

This commit modifies the build process to convert the `classes.jar` inside the Llama AAR to `classes.dex` *before* packaging it into the final `assets-*.zip` file. This is accomplished by using the D8 tool.

Changes include:
- Extracting `classes.jar` from the pre-built `llama-impl-*.aar`.
- Running the `d8` command-line tool to convert the JAR to a DEX file.
- Repackaging the AAR, replacing the original `classes.jar` with the newly generated `classes.dex`.
- Adding `dependsOn` to the `assembleV*Assets` tasks to ensure the Llama AARs are built first.
- In `LlmInferenceEngine`, `initialize()` is now called automatically if needed when loading a model, preventing a potential `Engine not initialized` error.

* feat(llama): Integrate llama.cpp as a native library

This commit integrates `llama.cpp` directly as a native library within the new `llama-impl` module, replacing the previous dynamic AAR loading mechanism.

Key changes:
- Adds a new `llama-impl` Android library module containing the C++ source, JNI bindings, and a `LLamaAndroid.kt` controller.
- Uses CMake to build `llama.cpp` and the JNI wrapper as part of the standard Gradle build process.
- The `createAssetsZip` task in `app/build.gradle.kts` is heavily refactored:
    - It now uses the D8 tool to compile the `llama-impl` module's `classes.jar` and all its dependencies into a `classes.dex` file.
    - The classpath for D8 is correctly constructed by resolving the `llama-impl` module's runtime configuration, ensuring all necessary classes are included.
- Core library desugaring is enabled for Java 17 compatibility.
- ProGuard is enabled for release builds in the `app` module.
- The `DynamicLibraryLoader` is updated to load `classes.dex` instead of `classes.jar`, simplifying the class loading process.

* feat(llama): Integrate llama.cpp as a native library

This commit integrates `llama.cpp` directly as a native library within the new `llama-impl` module, replacing the previous dynamic AAR loading mechanism.

Key changes:
- Adds a new `llama-impl` Android library module containing the C++ source, JNI bindings, and a `LLamaAndroid.kt` controller.
- Uses CMake to build `llama.cpp` and the JNI wrapper as part of the standard Gradle build process.
- The `createAssetsZip` task in `app/build.gradle.kts` is heavily refactored:
    - It now uses the D8 tool to compile the `llama-impl` module's `classes.jar` and all its dependencies into a `classes.dex` file.
    - The classpath for D8 is correctly constructed by resolving the `llama-impl` module's runtime configuration, ensuring all necessary classes are included.
- Core library desugaring is enabled for Java 17 compatibility.
- ProGuard is enabled for release builds in the `app` module.
- The `DynamicLibraryLoader` is updated to load `classes.dex` instead of `classes.jar`, simplifying the class loading process.

* feat: Update dependencies and improve Llama C++ implementation

This commit introduces several updates and fixes:

- Updates the Koin dependency to version 4.1.1 and moves it to the `libs.versions.toml` catalog for centralized version management.
- Removes unused `okhttp` and `kotlinx-serialization-json` dependencies from `app/build.gradle.kts`.
- Implements a more robust memory deallocation for `llama_batch` in the C++ layer to prevent memory leaks.
- Adds an error-handling mechanism in `llama-android.cpp` to throw a `java/lang/IllegalArgumentException` when the prompt size exceeds the model's context size, preventing native crashes.

* feat: Update dependencies and improve Llama C++ implementation

This commit introduces several updates and fixes:

- Updates the Koin dependency to version 4.1.1 and moves it to the `libs.versions.toml` catalog for centralized version management.
- Removes unused `okhttp` and `kotlinx-serialization-json` dependencies from `app/build.gradle.kts`.
- Implements a more robust memory deallocation for `llama_batch` in the C++ layer to prevent memory leaks.
- Adds an error-handling mechanism in `llama-android.cpp` to throw a `java/lang/IllegalArgumentException` when the prompt size exceeds the model's context size, preventing native crashes.

* build: Disable minification for release builds

This commit removes the ProGuard configuration for the `release` build type, effectively disabling code shrinking, obfuscation, and optimization.

The `isMinifyEnabled = true` flag and the `proguardFiles` configuration have been removed from the `release` block in `app/build.gradle.kts`.

* build: Disable minification for release builds

This commit removes the ProGuard configuration for the `release` build type, effectively disabling code shrinking, obfuscation, and optimization.

The `isMinifyEnabled = true` flag and the `proguardFiles` configuration have been removed from the `release` block in `app/build.gradle.kts`.

* refactor(agent): Decouple LlmInferenceEngine from native library and add initialization state

This commit refactors the `LlmInferenceEngine` to decouple it from the static `LLamaAndroid` library. The engine now dynamically loads the native library and its classes at runtime.

**Key Changes:**

-   **Dynamic Library Loading:** `LlmInferenceEngine` no longer directly accesses `LLamaAndroid.instance()`. Instead, it uses a `DynamicLibraryLoader` to get a `ClassLoader` and loads the "android.llama.cpp.LLamaAndroid" class via reflection.
-   **Engine Initialization State:** A new `initialize` method and `EngineState` (`Uninitialized`, `Initializing`, `Initialized`, `Error`) have been introduced. The engine must be successfully initialized before any models can be loaded or inference can be run.
-   **ViewModel and UI Updates:**
    -   `AiSettingsViewModel` now manages the `EngineState` and exposes it via LiveData.
    -   The `AiSettingsFragment` UI observes this state, disabling model selection buttons until the engine is initialized and displaying the current status (e.g., "Initializing engine...", "Engine is ready.").
    -   Model loading is now prevented if the engine is not ready.
-   **Interface-based Control:** The engine now interacts with the loaded llama instance through the `ILlamaController` interface, improving abstraction.
-   **Code Cleanup:** Unused methods and redundant logic in `AiSettingsViewModel` have been removed, and the view model's responsibility is now clearly focused on state management and orchestrating calls to the engine.

* refactor: Move shared string resources to the resources module

The following string resources have been moved from the `app` module to the shared `resources` module to promote reusability and centralize common text:

- `retry`
- `open_ai_settings`
- `new_chat`
- `ai_setting_initializing_engine`
- `ai_setting_engine_ready`

* refactor: Replace getBaseInstance() with baseInstance property access

* fix: support uncompressed llama AAR assets as fallback

- In `BundledAssetsInstaller`, try loading the uncompressed llama AAR asset if the Brotli-compressed version is not found.
- Add Gradle tasks `bundleV7LlamaAssets` and `bundleV8LlamaAssets` to extract `llama.aar` from the assets zip and copy it to the release assets directory.
- In the new Gradle tasks, attempt to compress the AAR with `brotli` if available; otherwise, copy it uncompressed.
- Hook these new bundling tasks into the build process (via `assembleV7Release` and `assembleV8Release`).

* ADFA-2149: Prevent crash when debug events occur before language client initialization (#660)

* feat(ADFA-2097): Do not show chooser when sending feedback email (#670)

* feat(ADFA-2097): Do not show chooser when sending feedback email

* fix(ADFA-2097): Set intent data

* ADFA-2163 | Fix undo enabled state on initial Layout Editor load (#663)

* fix(layout-editor): initialize undo stack correctly
Ensure undo enabled only after first modification

* fix(UndoRedoManager): Use value equality (==) instead of reference equality (===)

* integrate jacoco (#679)

* integrate jacoco for generating a project scope debug unit test coverage report

* clean up comments and commented code

* integrate jacoco for generating a project scope debug unit test coverage report

* clean up comments and commented code

* exclude llama-impl from coverage and bump version of jacoco to 0.8.11

* Improve installer display (#681)

* remove installing status and change FINISHED to green checkmark

* use plain green check instead of with box

* ADFA-2139: Add plugin sidebar slot limiting with manifest declaration and custom IdeNavigationRailView (max 12 items) (#674)

* ADFA-2139: Add plugin sidebar slot limiting with manifest declaration and custom IdeNavigationRailView (max 12 items)

* Fix sidebar slot leak when plugin loading fails after reservation

* ADFA-2139: Add scroll support for nav rail

* ADFA-2167: Fix ConstraintSet crash by ensuring all children have IDs before cloning (#669)

* ADFA-2195: Onboarding flow update (#677)

* feat(ADFA-2195): Add animation to next button

* feat(ADFA-2195): Show privacy dialog on permissions info screen

* refactor(ADFA-2195): Remove unused import

* feat(ADFA-2195): Add animation to finish installation button

* fix(ADFA-2195): Fix typos in function names

* ADFA-2116: reformat strings.xml and exclude it from Spotless formatting (#633)

* fix: formatting errors in strings.xml

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>

* fix: exclude strings.xml from Spotless

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>

* ADFA-2023 | Refactor layout positioning and drop/restore workflow (#606)

* feat(layouteditor): persist widget position on drop; save translationX/Y (dp) and restore on load
fix: clamp within container, add onDrop callback, and avoid re-applying default translation attrs

* refactor: Resolving BOT comments

* refactor: increase decimal places

* refactor: view parent

* refactor(layouteditor): Use ConstraintSet margins for view positioning
Replaces translationX/Y logic with persistent app:layout_marginStart/Top constraints

* FIX: Store and display properly widget positions, must fix jump at drop

* refactor(layout): extract constraint utilities and centralize position restore logic

Moves constraint helpers to ConstraintUtils.kt and integrates restorePositionsAfterLoad across editor and parser. This commit fixes ADFA-1439

* refactor(layout): optimize constraint batching and fix existing view drag-drop

* refactor(layouteditor): extract positioning utils; add drop/restore handlers and fix imports

* feat(LayoutEditor): add support for widgets positioning in GridLayout containers

* fix indent

* refactor(positioning): Optimize view restore to update only the moved view
Introduces `restoreSingleViewPosition` to avoid repositioning all views on drag/drop.

* fix(positioning): Fix indentation

* fix(layouteditor): Use android:layout_margin for universal ViewGroup compatibility

Replaced ConstraintLayout-specific 'app:layout_margin[Start/Top/End/Bottom]' with standard 'android:layout_margin[Start/Top/End/Bottom]' in the positioning logic to resolve build failures in non-ConstraintLayout containers.

* feat(layout-editor): add widget id sanitization for switch
prevent invalid ids by applying override map

* feat(layouteditor): add include marker support and update default widget icons

* fix: re-initialize AttributeInitializer on layout load to update map reference
Prevents writing to stale maps after undo/redo, fixing missing widget attributes

* ADFA-1616 | Improve Gemini API key handling and chat title logic (#684)

* feat: add clearer Gemini API key error message and adjust chat title logic
chore: update UI constraints for multiline tool execution status

* fix(agent): change critic role

* feat(agent): Add "X" mark to the API error message.

* ADFA-2170 | Fix initial TextView positioning behavior (#672)

* fix(layouteditor): ensure initial TextView uses absolute centered position
remove relative constraints and persist correct initial margins

* fix(layouteditor): Add safe calls and remove log

* ADFA-2168:  Fix ViewModel crash in detached fragment by using guarded isEmpty setter (#686)

ADFA-2168: ⏺ Fix ViewModel crash in detached fragment by using guarded isEmpty setter

* Enable StrictMode for debug builds. (#691)

* Enable StrictMode for debug builds.

* Enable StrictMode for debug builds.

* Move enabling of StrictMode to DeviceProtectedApplicationLoader.

* remove unused import and cleanup indentation

* crash the app on all StrictMode violations (#693)

* penaltyLog instead of penaltyDeath in debug builds on presence of feature flag file (#696)

* penaltyLog instead of penaltyDeath in debug builds when the feature flag file CodeOnTheGo.a3s19 is preesent in Download folder

* make file existence check conform to strictmode disk access policy

* rename variable

* ADFA-2128: Handle IllegalArgumentException when previewing NavigationView (#636)

* fix(ADFA-2128): Show error when navigation view is not a child of DrawerLayout

* feat(ADFA-2128): Add support for DrawerLayout in layout editor

* fix(ADFA-2128): Add missing resource

* Minor fixes

* ADFA-2165: Audit layout editor (#673)

* refactor(ADFA-2165): Optimise imports in layouteditor module

* refactor(ADFA-2165): Remove unused activities

* refactor(ADFA-2165): Remove unused files

* Revert "refactor(ADFA-2165): Remove unused files"

This reverts commit 368ef9ff1809fb3d5a6450054857b9d99f13ac9f.

* refactor(ADFA-2165): Remove unused library

---------

Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>

* ADFA-2233 | Fix core-ktx version and re-enable llama-impl in Jacoco (#694)

feat(build): align core-ktx version and re-enable llama-impl for jacoco
Ensures compatibility with current AGP and resolves metadata conflicts

* ADFA-2092: gradle sync error during initialization is incorrectly reported as success (#648)

* fix: initialization failures are incorrectly reported as success
* fix: consider sync file readability when deciding whether to sync
* fix: inverted condition check for areSyncFilesReadable
* fix: missing notifyBuildSuccess call

---------

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>

* ADFA-2248 | Implement created/modified date logic across project components (#689)

* feat: implement created/modified date handling across project adapters
fix: unify date formatting and add lastModified persistence

* refactor: improve created/modified date logic and label consistency
fix: update ordering, labels and rendering

* feat(projects): add DB migration, async file attribute handling, safe calls and fix indentation

* refactor: centralize date rendering and improve project loading UX

* refactor: rename Date.kt to DateFormatter.kt for clearer intent

* ADFA-2230: Fix broken unit test (#690)

* fix(ADFA-2230): Fix broken unit test

* feat(ADFA-2230): Include xml-inflater project

* feat(ADFA-2230): Include previously excluded projects from Jacoco task

* ADFA-2262: Fix compatibility issues (#692)

fix(ADFA-2262): Use a backwards-compatible method

Co-authored-by: Hal Eisen <haleisen@appdevforall.org>

* fix(ADFA-2290): Initialize property before accessing (#704)

* ADFA-2180: Fix ArrayIndexOutOfBoundsException: index = 1, length = 1 on ContentExt.kt (#687)

* ADFA-2224: Fix IllegalStateException: Fragment MainFragment (#682)

* ADFA-2158 Ignore /bin/ directories; ignore IDE directories (#701)

Ignore /bin/ directories; ignore IDE directories

* ADFA-2292 Attempt to extract Jira key from the commit message in debug.yml (#705)

Attempt to extract Jira key from the commit message in debug.yml

* ADFA-1966: Move file operations to background thread (#688)

* fix(ADFA-1966): Move plugin installation file I/Os to background

* fix(ADFA-1966): Move screenshot file I/Os to background

* fix(ADFA-1966): Clean up resources

* fix(ADFA-1966): Clean up temp file in case of exception

* ADFA-2157: Fix tooltip crash when activity is destroyed or view detached (#664)

* ADFA-2157: Fix tooltip crash when activity is destroyed or view detached

* return false for activityValid check

* ADFA-2284 Push the 4am nightly build to a directory on the website (#711)

* upload apks to greengeeks apk_repo folder

* disable notification for test runs

* disable distribution to firebase for test

* finalize and clean out test scaffolding

* make variable names clearer and cleanup ssh key and hosts

* remove unnecessary code

---------

Co-authored-by: Hal Eisen <haleisen@appdevforall.org>

* ADFA-2206: Fix NPE in asset installation when zip entry is missing (#699)

* ADFA-2206: Fix NPE in asset installation when zip entry is missing

* ADFA-2206: Display specific error message in flash message

* ADFA-2206: Display specific error message in flash message

* ADFA-2206: Display specific error message in flash message

* ADFA-2312: Fix StringIndexOutOfBoundsException in DimensionUtil.getDimenWithoutSuffix (#714)

Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>

* ADFA-2264 automate adding fix version YY.ww to Jira ticket on merge to stage (#715)

* ADFA-2264 automate adding fix version YY.ww to Jira ticket on merge to stage

* More secure and accurate head refs in .github/workflows/debug.yml

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Addresses CodeRabbit's suggestion for more clear handling of NEXT_RELEASE_VERSION

* Fix jq install location

* Move initialization of NEXT_RELEASE_VERSION

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* ADFA-2247 | Add search, sorting, and filtering UI for saved projects (#700)

* feat(ui): add search bar and sort controls to saved projects screen
feat: include new icons and string resources for sorting options

* feat(projects): implement search and sorting via new filter sheet
Refactor UI and ViewModel to support dynamic filtering and updated layouts

* feat(projects): add Doc Strings, changing btn background and text and change direction btn design

* feat(projects): remove commented line and added a todo

* refactor: remove the unimplemented `date modified` filter and add comments to add it later.

* refactor: add `date modified` filter to recent projects page

* fix(recent_projects): Replace delay with events and native debounce

* refactor(sorting): Use data class instead of Triple

* refactor(recent_projects): Refactoring UI: everything related to “filtering” was removed, since we are only sorting. Replaced icons with Material icons

* refactor(recent-projects): Make `applyFilters` run on the CPU thread

* feat(recent-projects): Add string for screen reader users

* refactor(recent-projects): Using `requireViewById` instead of `findViewById`

* ADFA-2264 Attempt to fix broken build by looking for Jira ticket key in more places (#720)

* ADFA-2264 Attempt to fix broken build by looking for Jira ticket key in more places

* Simplify grep looking for ticket key

* ADFA-2323-Change-caps-in-Developer-options-pref (#722)

Correct string casing for 'Developer Options'

* fix(ADFA-2280): Display search results on first search (#712)

* fix(ADFA-2280): Display search results on first search

* fix(ADFA-2280): Rework solution

* refactor(ADFA-2280): Remove redundant adapter setting

---------

Co-authored-by: Hal Eisen <haleisen@appdevforall.org>
Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>

* ADFA-1304 | Add Project Info Bottom Sheet (#706)

* feat: add full project info bottom sheet with details and DB migration
includes UI, tooltips, parser utils, and RecentProjects integration

* refactor(project_info): Remove duplicated code, remove unused imports, fix indentation and added KDocs to InfoRowView.kt

* fix(recent_projects): Fix indentation

* refactor(project-info): enforce I/O safety and simplify InfoRowView usage

- Make build version utility functions `suspend` and `Main-Safe` using `Dispatchers.IO` to comply with StrictMode.
- Add `setLabelAndValue` helper to `InfoRowView` and update `ProjectInfoBottomSheet` to reduce boilerplate.
- Remove redundant XML comments.

* refactor(project-info): Improve the loading time of project information

* refactor(projects_info): Improve UI/UX for close button

* feat: improve Kotlin version detection in project details

Enhances readKotlinVersion to read versions from app Gradle files and libs.versions.toml when root directory is passed

* refactor: Improve Kotlin detection for project info panel

* resolve merge conflicts

---------

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>
Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>
Co-authored-by: Daniel-ADFA <danielalome@appdevforall.org>
Co-authored-by: Dara Abijo <oluwadara.abijo@appdevforall.org>
Co-authored-by: jomen-adfa <joelmenchavez@appdevforall.org>
Co-authored-by: itsaky-adfa <akashyadav@appdevforall.org>
Co-authored-by: Hal Eisen <haleisen@appdevforall.org>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Elissa-AppDevforAll <elissamiller@appdevforall.org>

* wip: refactor CV experimental

* cleanup

* Change GenerageXMLAction.kt to modify the tag for computer vision icon.

* Added floating action button to computer visoin

---------

Signed-off-by: Akash Yadav <akashyadav@appdevforall.org>
Co-authored-by: rasnarim <rasnarim@gmail.com>
Co-authored-by: Daniel Alome <danielalome@appdevforall.org>
Co-authored-by: John Andrés Trujillo <34223334+jatezzz@users.noreply.github.com>
Co-authored-by: Dara Abijo <oluwadara.abijo@appdevforall.org>
Co-authored-by: jomen-adfa <joelmenchavez@appdevforall.org>
Co-authored-by: itsaky-adfa <akashyadav@appdevforall.org>
Co-authored-by: Hal Eisen <haleisen@appdevforall.org>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Elissa-AppDevforAll <elissamiller@appdevforall.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments