Skip to content

feat(formulus): support settings deep links - #1009

Open
allennakalema06-web wants to merge 15 commits into
OpenDataEnsemble:devfrom
allennakalema06-web:feat/formulus-settings-deep-link
Open

allennakalema06-web wants to merge 15 commits into
OpenDataEnsemble:devfrom
allennakalema06-web:feat/formulus-settings-deep-link

Conversation

@allennakalema06-web

@allennakalema06-web allennakalema06-web commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Implements #915 by wrapping Formulus settings QR payloads in a 'formulus://settings?payload=...' deep link, allowing Android users to scan settings QR codes using their device camera and open Formulus.

Existing bare 'FRMLS:' payloads remain supported.

Changes

  • Registers the 'formulus://settings' deep link on Android.
  • Routes incoming settings deep links to the Profiles flow.
  • Processes extracted FRMLS payloads directly through 'QRSettingsService.processPayload()'.
  • Prefills the Add Profile form without automatically creating a profile or persisting credentials.
  • Prevents incoming deep links from overwriting an unfinished profile.
  • Supports trailing slashes and additional query parameters in settings links.
  • Rejects malformed URL encoding, duplicate payload parameters, and unexpected deep-link paths.
  • Preserves backward compatibility with existing bare 'FRMLS:' QR codes.
  • Updates the Formulus QR generator, Synkronus Portal, and 'synk qr' to generate URI-wrapped payloads by default.
  • Adds tests for deep-link parsing, profile prefilling, and unfinished-profile protection.

Platform Support and Compatibility

Android

This PR implements Android-first support for camera-scannable settings QR codes.

The new QR format requires an Android Formulus build containing this PR. Formulus 1.4.0 (version code 108) does not include this feature.

The minimum supported release version will be identified when the implementation is included in an official release.

Backward Compatibility

Existing bare 'FRMLS:' QR codes remain supported by the in-app scanner.

The new 'formulus://settings?payload=...' format is the default for QR generation. An optional '--legacy' generator flag can be considered in a follow-up for users running older Formulus builds.

iOS

iOS deep-link support is deferred to a separate follow-up.

The previously added 'CFBundleURLTypes' registration has been removed. Full iOS support requires forwarding incoming URLs through the application's scene lifecycle to React Native's linking handler, followed by physical-device testing.

This PR does not claim iOS camera-scanning support.

Validation

  • QRSettingsService tests: 10 passed.
  • ProfilesScreen tests: 32 passed.
  • Total targeted tests: 42 passed, 0 failed.
  • Android manifest processing: passed during initial implementation.
  • TypeScript checks for the originally changed Formulus application files: passed during initial implementation.
  • 'git diff --check': passed.
  • Formulus QR generator manually verified to emit 'formulus://settings?payload=...'.
  • Physical Android testing confirmed that Android recognizes the settings deep-link intent and launches Formulus.
  • Full end-to-end profile-prefill verification on the physical device remains unverified because of a local Metro dependency-resolution issue ('invariant').

Release Notes

For the first Android release containing this PR:

  • Settings QR codes can be scanned using the Android device camera to open Formulus.
  • Scanned settings prefill the Add Profile form and require user confirmation before saving.
  • Existing in-app 'FRMLS:' QR scanning remains supported.
  • Camera-scannable settings QR codes require this release or a later compatible Android build.
  • iOS camera-scanning support is not included.

@Mishael-2584 Mishael-2584 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks @allennakalema06-web, the approach is good: it reuses the existing confirmation flow and keeps bare FRMLS: scanning working.

Two things to resolve before merge: iOS delivery of the link, and how older app versions handle the new QR format. I've also left a few smaller suggestions inline.

@Mishael-2584
Mishael-2584 self-requested a review October 6, 2026 11:35
Comment thread formulus/ios/Formulus/Info.plist Resolved
Comment thread synkronus-portal/src/utils/frmls.ts Resolved
Comment thread formulus/src/screens/ProfilesScreen.tsx Resolved
Comment thread formulus/src/screens/ProfilesScreen.tsx Resolved
@allennakalema06-web

Copy link
Copy Markdown
Contributor Author

Hi @Mishael-2584,

Thank you for the detailed review and guidance!

I've pushed updates addressing your feedback:

  • Added 'processPayload()' to process the already-decoded FRMLS payload directly.
  • Added protection against incoming links overwriting an unfinished profile.
  • Improved deep-link parsing to support trailing slashes and additional query parameters, with validation for malformed encoding.
  • Removed the iOS URL-scheme registration and clarified that this PR is Android-only.
  • Updated the PR description with compatibility requirements, backward compatibility, and release-note wording.
  • Added the missing Swahili translation identified during CI testing.

All GitHub Actions checks are now passing, including the Formulus React Native tests and Android build.

The optional '--legacy' generator flag is deferred for a follow-up, as discussed.

Could you please take another look when you have time and let me know if anything else needs adjustment?

Thanks again!

@Mishael-2584

Copy link
Copy Markdown
Contributor

Thanks @allennakalema06-web. Great work! The updates address our earlier feedback, and both the React Native tests and Android build are passing.

Please make one small adjustment in ProfilesScreen.tsx:

The deep-link effect depends on editor, but it also updates editor. This can trigger another effect run while the payload is still present, potentially showing “Finish or cancel the current profile…” immediately after successfully prefilling the form.

  1. Change the initial if (editor) guard to if (editorRef.current).
  2. Remove editor from that effect’s dependency array. Keep the existing editorRef synchronization and the guard after await.
  3. In “incoming deep link prefills a new profile without saving”, add this assertion after checking the prefilled fields:

expect(ToastService.showLong).not.toHaveBeenCalled();

Please rerun the ProfilesScreen and QRSettingsService end to end tests afterward on a physical android device using the debug APK built with the metro bundler. I see you mentioned in this PR that there were issues with your metro bundler because of some dependencies? If you need some assistance setting that up, let us know. We expect that a full successful test would be a QR code being scanned from the phone's native camera. Once the adjustment and device verification are complete, we’ll merge that in. Thank you for the great work on this amazing feature!

@najuna-brian najuna-brian moved this from Triage to In progress in ODE Community Board Oct 27, 2026
@allennakalema06-web

Copy link
Copy Markdown
Contributor Author

Hi @Mishael-2584,

Thank you for the detailed feedback and encouragement!

I've pushed the requested adjustments in commit 'fdf7a70e':

  • Updated the initial deep-link guard to use 'editorRef.current' and removed 'editor' from the effect dependencies, while preserving the existing ref synchronization and post-await guard.
  • Added the assertion verifying that no unexpected toast appears when an incoming deep link successfully prefills a new profile.

I reran both the 'ProfilesScreen' and 'QRSettingsService' test suites locally, and all 42 tests passed.

Unfortunately, I'm unable to complete the physical Android verification on my machine because of limited storage and the absence of a configured Android SDK/ADB environment. I don't want to claim that the native-camera QR flow has been verified when it hasn't.

Would it be possible for someone with an existing Android development setup to help verify the end-to-end flow on a physical device?

Thank you again for your guidance and support!

@Mishael-2584

Copy link
Copy Markdown
Contributor

Thanks @allennakalema06-web. The editorRef adjustment looks good. I added the remaining no-toast assertion to the incoming deep-link test in bef9b8c and reran both suites: all 42 tests passed.

We’ll handle the physical Android verification on the maintainer side, then merge once that and CI are complete. @najuna-brian

otherwise code review complete from me thanks for the good work.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

3 participants