Skip to content

ADFA-3492 | Fix ProjectFile NPE in resource fragments#1341

Merged
jatezzz merged 2 commits into
stagefrom
fix/ADFA-3492-npe-resource-fragments
May 28, 2026
Merged

ADFA-3492 | Fix ProjectFile NPE in resource fragments#1341
jatezzz merged 2 commits into
stagefrom
fix/ADFA-3492-npe-resource-fragments

Conversation

@jatezzz
Copy link
Copy Markdown
Collaborator

@jatezzz jatezzz commented May 26, 2026

Description

Resolves a NullPointerException occurring in ColorFragment (and other resource fragments) when attempting to access ProjectFile methods like getColorsPath() on a null object reference. This PR introduces a ProjectResolver to safely resolve the project instance from ProjectManager or the fragment arguments. Additionally, it transitions the resource fragments to use the newInstance pattern, ensuring the ProjectFile is securely passed and retained across the fragment's lifecycle.

Details

  • Created ProjectResolver.java to handle safe project data extraction and display graceful error states if the project is null.
  • Updated ColorFragment, DrawableFragment, FontFragment, and StringFragment to use a newInstance(ProjectFile) method instead of relying solely on the singleton or non-default constructors.
  • Refactored ResourceManagerActivity to handle project intent loading correctly using IntentCompat and cleaned up its options menu action logic.

Before

Screen.Recording.2026-05-26.at.3.07.19.PM.mov

After

Screen.Recording.2026-05-26.at.3.40.42.PM.mov

Ticket

ADFA-3492

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8f760102-e317-4244-970c-c426d8b51fe9

📥 Commits

Reviewing files that changed from the base of the PR and between 94d948f and 07c4ec4.

📒 Files selected for processing (6)
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/ColorFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/DrawableFragment.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/FontFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/StringFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java
🚧 Files skipped from review as they are similar to previous changes (6)
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/ColorFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/StringFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/FontFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/DrawableFragment.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt

📝 Walkthrough
  • Bug fixes

    • Prevented NullPointerException in resource fragments (ColorFragment, DrawableFragment, FontFragment, StringFragment) by ensuring ProjectFile is resolved and non-null before UI/data setup; fragments now early-return and show a graceful error when no project is available.
  • Changes

    • Project resolution
      • Added ProjectResolver utility to resolve ProjectFile from fragment arguments (Constants.EXTRA_KEY_PROJECT) with a fallback to ProjectManager.getInstance().getOpenedProject(), and to show a user-facing error when resolution fails.
      • Fragments now call ProjectResolver.getValidProjectOrShowError(arguments, view) in onViewCreated().
    • Fragment API / lifecycle
      • Resource fragments switched to newInstance(ProjectFile) factory pattern:
        • ColorFragment.newInstance(ProjectFile)
        • DrawableFragment.newInstance(ProjectFile)
        • FontFragment.newInstance(ProjectFile)
        • StringFragment.newInstance(ProjectFile)
      • DrawableFragment removed its constructor parameter and now manages drawableList internally.
      • FontFragment onDestroyView() now null-checks executor before shutdown and clears view binding.
    • Activity refactor
      • ResourceManagerActivity reads ProjectFile from Intent via IntentCompat.getParcelableExtra(intent, Constants.EXTRA_KEY_PROJECT, ProjectFile::class.java) with fallback to ProjectManager.instance.openedProject; finishes if none found and opens the resolved project if it differs from the currently opened one.
      • setupViewPager() now instantiates resource fragments via their newInstance(currentProject) factories.
      • Options/menu handling moved to helper methods; "add resource" flows include a legacy photo picker fallback for pre-Tiramisu devices.
      • Viewing XML for colors/strings now reads files directly from currentProject.colorsPath/currentProject.stringsPath (FileUtil.readFile) and launches ShowXMLActivity with the file content.
    • File-picking and add flows
      • Photo/font/XML pickers and handlers keep existing behavior but route results to the active pager fragment (found by tag) and call fragment-specific add* methods.
      • XML drawable imports validate vector content (VectorMasterDrawable) before adding.
  • Files changed (high level)

    • layouteditor/src/.../ResourceManagerActivity.kt
    • layouteditor/src/.../fragments/resources/ColorFragment.java
    • layouteditor/src/.../fragments/resources/DrawableFragment.kt
    • layouteditor/src/.../fragments/resources/FontFragment.java
    • layouteditor/src/.../fragments/resources/StringFragment.java
    • layouteditor/src/.../utils/ProjectResolver.java
  • Risk Assessment & Best-practice notes

    • Improvements
      • Passing ProjectFile via fragment arguments and using newInstance(...) follows Android lifecycle best practices and reduces NPE risk.
      • Centralizing resolution and error presentation in ProjectResolver reduces duplicated logic and standardizes error UI.
    • Remaining risks / considerations
      • ProjectResolver still falls back to a ProjectManager singleton; the singleton anti-pattern is encapsulated but not removed—consider removing singleton reliance long-term.
      • Ensure all fragments and background tasks tolerate early exits to avoid unfinished work, leaked resources, or executor race conditions.
      • Verify IntentCompat.getParcelableExtra(...) behavior across targeted API levels and Parcelable implementation versions.
      • Confirm the user-facing error flows (SBUtils/message overlays) are not overly repetitive or disruptive in edge cases.
      • Add tests for project-missing flows and for parceling ProjectFile in intents to prevent regressions.
  • Public API notes

    • No breaking public API changes detected; added newInstance(ProjectFile) factory methods for resource fragments.

Walkthrough

Centralizes project resolution with ProjectResolver; converts Color/Drawable/Font/String fragments to factories accepting ProjectFile via arguments; updates ResourceManagerActivity to resolve/open the project from the intent, build the pager with fragment.newInstance(currentProject), and refactor menu and picker flows.

Changes

Resource Fragment and Activity Refactoring

Layer / File(s) Summary
ProjectResolver utility foundation
layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java
Adds ProjectResolver with resolveProject(Bundle) to fetch a ProjectFile from fragment/intent extras or fallback to ProjectManager, and getValidProjectOrShowError(Bundle, View) to resolve and optionally show an error.
Resource fragments factory adoption
layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/ColorFragment.java, .../DrawableFragment.kt, .../FontFragment.java, .../StringFragment.java
Each fragment adds newInstance(ProjectFile) to place the project into arguments, replaces direct ProjectManager access with ProjectResolver.getValidProjectOrShowError(arguments, view) in onViewCreated, returns early if unresolved, updates imports; DrawableFragment removes constructor param and manages drawable list internally; FontFragment guards executor shutdown.
ResourceManagerActivity integration and UI flow
layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt
Activity reads ProjectFile from intent extra (fallback to ProjectManager.instance.openedProject), opens the resolved project when paths differ, builds the view pager using *.newInstance(currentProject), refactors menu handling into helpers (handleAddResourceAction, handleViewXmlAction, showErrorState), adds SDK-aware drawable-type chooser fallback, and updates picker result handlers and permission flows.

Sequence Diagram

sequenceDiagram
  participant ResourceManagerActivity
  participant ProjectResolver
  participant ProjectManager
  participant DrawableFragment

  ResourceManagerActivity->>ProjectResolver: resolveProject(intent.extras)
  ProjectResolver-->>ResourceManagerActivity: ProjectFile or null
  alt resolved && different path
    ResourceManagerActivity->>ProjectManager: openProject(resolvedProject)
    ProjectManager-->>ResourceManagerActivity: opened
  end
  ResourceManagerActivity->>DrawableFragment: adapter.add(DrawableFragment.newInstance(currentProject))
  DrawableFragment->>ProjectResolver: getValidProjectOrShowError(arguments, view)
  ProjectResolver-->>DrawableFragment: ProjectFile or null
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • itsaky-adfa
  • dara-abijo-adfa
  • Daniel-ADFA

Poem

🐰 I found the project in a nibble of night,
Arguments tucked in, fragments set right,
Resolver hummed softly, opened the door,
The pager hopped forward to add one more,
A tidy garden of resources—what a sight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically identifies the main change: fixing a ProjectFile NullPointerException in resource fragments.
Description check ✅ Passed The description comprehensively explains the NullPointerException issue, the ProjectResolver solution, and the newInstance pattern refactoring applied across resource fragments.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ADFA-3492-npe-resource-fragments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
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: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt`:
- Around line 63-65: The current logic uses
ProjectManager.instance.openedProject as primary and falls back to the intent,
which can ignore an explicitly requested project; change the assignment so
project is set from the IntentCompat.getParcelableExtra(...) result
(projectExtra) first, and then update/sync ProjectManager.instance.openedProject
to that project (or call ProjectManager.instance.openProject/openedProject
setter) so both the activity and ProjectManager reference the intent project;
apply the same change to the other occurrence(s) that currently use
openedProject ?: projectExtra (lines around the ProjectManager usage).
- Around line 205-207: The case for option 1 only calls launchPhotoPicker()
behind an API >= TIRAMISU check, so on API < 33 the option does nothing; update
the branch to handle legacy devices by invoking a fallback picker for older APIs
(e.g., call launchPhotoPicker() for API >= Build.VERSION_CODES.TIRAMISU and call
a new or existing legacy method such as launchPhotoPickerLegacy() or
startActivityForResult/Intent ACTION_PICK / ACTION_OPEN_DOCUMENT targeting
MediaStore.Images.Media.EXTERNAL_CONTENT_URI for API < TIRAMISU). Modify the
ResourceManagerActivity's selection handling (the switch/case that currently
references launchPhotoPicker()) and add the legacy picker helper (or reuse an
existing gallery/open-document helper) so image drawable selection works on
pre-Android 13 devices.

In
`@layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/FontFragment.java`:
- Around line 71-73: onViewCreated may return early when
ProjectResolver.getValidProjectOrShowError(...) yields null leaving the field
executor uninitialized, so update onDestroyView to guard the teardown: check
that executor is non-null (and optionally not already shutdown/terminated)
before calling executor.shutdownNow(), and set executor to null after shutdown;
reference the executor field and the lifecycle methods
onViewCreated/onDestroyView and the ProjectResolver.getValidProjectOrShowError
call when making the change.

In
`@layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java`:
- Around line 15-18: resolveProject() currently prefers the singleton
ProjectManager.getInstance().getOpenedProject() which can ignore an explicitly
provided fragment argument; change the lookup order to first check
arguments.getParcelable(Constants.EXTRA_KEY_PROJECT) (or equivalent fragment
arguments retrieval) and return it if non-null, otherwise fall back to
ProjectManager.getInstance().getOpenedProject(); ensure null-safe handling of
arguments and the parcelable cast to avoid NPEs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f12afb07-7bb8-4223-b21c-0ce41d23d2f8

📥 Commits

Reviewing files that changed from the base of the PR and between 99d896f and 3ad5664.

📒 Files selected for processing (6)
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/ColorFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/DrawableFragment.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/FontFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/StringFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java

Copy link
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java`:
- Around line 15-16: In ProjectResolver.resolveProject replace the deprecated
call to arguments.getParcelable(Constants.EXTRA_KEY_PROJECT) and the redundant
containsKey check: use BundleCompat.getParcelable(arguments,
Constants.EXTRA_KEY_PROJECT, YourProjectClass.class) (or the actual Parcelable
class used) to retrieve the project in a type-safe, API-33-compatible way;
ensure you import androidx.core.os.BundleCompat and return the result cast to
the expected type (or declared generically) from resolveProject.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ccd0bbbe-507a-4a49-8522-df268250881c

📥 Commits

Reviewing files that changed from the base of the PR and between 3ad5664 and eceb94f.

📒 Files selected for processing (3)
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/FontFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/FontFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt

@jatezzz jatezzz force-pushed the fix/ADFA-3492-npe-resource-fragments branch from eceb94f to 94d948f Compare May 28, 2026 13:05
Copy link
Copy Markdown
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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/ColorFragment.java`:
- Around line 56-60: The factory method ColorFragment.newInstance currently
always puts Constants.EXTRA_KEY_PROJECT into the fragment arguments even when
project is null, which prevents ProjectResolver.resolveProject from falling back
to ProjectManager; modify newInstance so it only calls
args.putParcelable(Constants.EXTRA_KEY_PROJECT, project) (or sets the argument
key) when project != null (or alternatively validate/enforce a non-null Project
parameter) so that resolveProject can correctly detect absence of the key and
use ProjectManager.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2ad6c097-6947-43cd-a12b-5e9506aad363

📥 Commits

Reviewing files that changed from the base of the PR and between eceb94f and 94d948f.

📒 Files selected for processing (6)
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/ColorFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/DrawableFragment.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/FontFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/StringFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java
🚧 Files skipped from review as they are similar to previous changes (5)
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/StringFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/utils/ProjectResolver.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/DrawableFragment.kt
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/fragments/resources/FontFragment.java
  • layouteditor/src/main/java/org/appdevforall/codeonthego/layouteditor/activities/ResourceManagerActivity.kt

jatezzz added 2 commits May 28, 2026 14:59
…agments

Introduces ProjectResolver to safely fetch project instances and handle null states
@jatezzz jatezzz force-pushed the fix/ADFA-3492-npe-resource-fragments branch from 94d948f to 07c4ec4 Compare May 28, 2026 19:59
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

Actionable comments posted: 0

@jatezzz jatezzz merged commit 3a7c784 into stage May 28, 2026
2 checks passed
@jatezzz jatezzz deleted the fix/ADFA-3492-npe-resource-fragments branch May 28, 2026 20:54
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.

2 participants