Skip to content

Feat: Upgrade to React Native 0.86 (New Architecture / TurboModule) + SPM opt-in for ZelloSDK#28

Merged
rxmichael merged 41 commits into
developfrom
michael/feat/turbomudle
Jul 7, 2026
Merged

Feat: Upgrade to React Native 0.86 (New Architecture / TurboModule) + SPM opt-in for ZelloSDK#28
rxmichael merged 41 commits into
developfrom
michael/feat/turbomudle

Conversation

@rxmichael

@rxmichael rxmichael commented Jun 16, 2026

Copy link
Copy Markdown

Summary

Upgrades the SDK from React Native 0.74.5 to 0.86 on the New Architecture, converts the native modules to a Turbo Native Module, and adds an opt-in Swift Package Manager path for ZelloSDK. Released as 3.0.0 (breaking).

IOS-4249

What changed

  • RN 0.86 + New Arch: React 19, Node 22 toolchain, Android Gradle (SDK 36, Kotlin 2.1.20, Gradle 9.3.1, AGP 8.13), jest preset, eslint/prettier, builder-bob 0.42.
  • TurboModule: one shared codegen spec (src/specs/NativeZelloSdk.ts); iOS reimplemented as an ObjC++ module forwarding to Swift; Android ZelloAndroidSdkModule reimplemented against NativeZelloSdkSpec. JS de-branched (~25 Platform.OS sites) onto the unified module; getHistory/getHistoryImageData are now Promises; events flow over the bridgeless-safe DeviceEventEmitter.
  • SPM (opt-in, Sentry-style): ZELLO_USE_SPM=1 pulls ZelloSDK from zelloptt/ios-mobile-sdk (ZelloSDKUmbrella) via spm_dependency. CocoaPods stays the default. Full CocoaPods removal isn't possible on RN 0.86 (RN still requires it — RFC #994).
  • Docs: README install paths + the CocoaPods BUILD_LIBRARY_FOR_DISTRIBUTION requirement for Xcode 16/26+; CHANGELOG 3.0.0.

Verified

  • iOS, end to end: builds (CocoaPods and SPM), launches on simulator, methods + events confirmed against a live Zello login.
  • ✅ typecheck / lint / Metro bundle / bob build.

Needs CI (couldn't build locally — no Android toolchain)

  • Android builds (Gradle) on New Arch.
  • Confirm connectGroupConversation — assumes zello.connectChannel(...) accepts a ZelloGroupConversation (flagged in code).
  • Android on-device smoke test (connect + an event).

Breaking

  • Requires RN 0.86+ with the New Architecture; drops the legacy bridge. Node 20+ (22+ recommended).

⚠️ Do not publish 3.0.0 until Android is green in CI.

Follow-ups (non-blocking)

  • Wire the NotificationServiceExtension to ZelloSDKUmbrella in SPM mode.
  • Dev-only RCTEventEmitter.receiveEvent red box (third-party view-interop, not the SDK).
  • EventEmitter deep-import lint warning in src/sdk/index.ts:43.

zello-n and others added 30 commits June 17, 2025 17:08
Increase Android SDK to 1.0.+ (1.0.4)
The example app pins iOS to UIUserInterfaceStyle=Light but Android
used Theme.AppCompat.DayNight, so on Android in dark mode the
hardcoded white modal dialogs rendered with the system white text,
making content invisible. Match iOS by using the Light theme.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add a pod install-time deprecation warning to the podspec and a README notice. CocoaPods still works and remains supported; Swift Package Manager is the recommended installation path going forward.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Upgrade the library and example app from RN 0.74.5 to 0.86.0 (React 19.2.3).

JS/tooling:
- Bump RN, React, @react-native/* tooling, builder-bob 0.42, TypeScript 5.8
- Require Node >= 22.11 (.nvmrc -> v22)
- Switch example SDK dep from file:.. to link:.. (avoids yarn pack OOM)
- Map scoped package name to ./src in tsconfig paths
- Migrate jest preset to @react-native/jest-preset
- Fix eslint via plugin:prettier/recommended (0.86 config dropped the plugin)
- Use requestNotifications() on Android (rn-permissions v5 dropped POST_NOTIFICATIONS)
- Bump example deps (navigation 7, screens 4, safe-area-context 5, firebase 24, etc.)

Android (config only, not build-verified - no local JDK/SDK):
- SDK 36, buildTools 36.0.0, NDK 27.1.12297006, Kotlin 2.1.20, Gradle 9.3.1
- AGP 8.13.0, Hilt/Dagger 2.56.2, newArchEnabled=true

Verified: typecheck, lint, bob build, and Metro JS bundle all pass.
Native builds pending the TurboModule conversion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a single codegen spec (src/specs/NativeZelloSdk.ts) that both
platforms will implement, replacing the two divergent legacy bridge modules.

- configure takes one object param; getHistory/getHistoryImageData are Promises
- events stay off the spec, emitted on the global DeviceEventEmitter 'zellosdk' channel
- wire codegenConfig (RNZelloSdkSpec, outputDir ios/android); add @react-native-community/cli
- mark create-react-native-library type as turbo-module; gitignore generated output

Validated: 'yarn bob build --target codegen' generates the iOS NativeZelloSdkSpec
protocol and Android NativeZelloSdkSpec.java. Native impls and JS rewiring follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the iOS TurboModule conforming to the generated NativeZelloSdkSpec:
- ZelloSdkModule.{h,mm}: ObjC++ module, RCT_EXPORT_MODULE(NativeZelloSdk),
  getTurboModule -> NativeZelloSdkSpecJSI, forwards all 29 methods to Swift
- ZelloSdkModuleImpl.swift: Swift impl calling Zello.shared; configure takes
  an object param, getHistory/getHistoryImageData use resolve/reject
- The existing ZelloIOSSdkModule RCTEventEmitter is left intact for events
  (both share the Zello.shared singleton, no event-layer rewrite needed)
- Fix create-react-native-library type to module-new

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The generated NativeZelloSdkSpec header is Obj-C++ only, but ZelloSdkModule.h
is pulled into the pod's Swift umbrella. Move the spec import and protocol
conformance into ZelloSdkModule.mm via a class extension, leaving the public
header free of C++. Also exclude ios/generated (local bob codegen output) from
the podspec so it is never compiled by the host app.

Verified: the react-native-zello-sdk pod and both new files now compile clean
in the example iOS build.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace per-platform NativeModules method calls in src/sdk/index.ts with the
unified NativeZelloSdk TurboModule: collapse ~25 Platform.OS branches to single
calls, pass the whole config object to configure, and use the returned Promise
for getHistory/getHistoryImageData. ZelloAndroidSdkModule/ZelloIOSSdkModule are
kept only for the event emitter.

Verified: typecheck, lint, and Metro bundle pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Import the pod's Swift header framework-style (use_frameworks!) via __has_include
- Drop BUILD_LIBRARY_FOR_DISTRIBUTION=YES from the Podfile post_install: it forced
  Swift module-interface verification that broke RNScreens under use_frameworks!
- Regenerate Podfile.lock / project for RN 0.86 pods (prebuilt core, Hermes, SPM
  integration); gitignore the machine-local .xcode.env.local

Verified: 'xcodebuild ... -sdk iphonesimulator build' => BUILD SUCCEEDED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Under the bridgeless New Architecture, RCTEventEmitter's sendEvent/receiveEvent
path is not callable. Emit the unified 'zellosdk' event through the global
RCTDeviceEventEmitter via the injected RCTCallableJSModules (matching how the
Android module already emits), and subscribe on the JS side with
DeviceEventEmitter instead of new NativeEventEmitter(module).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Gemfile: allow CocoaPods 1.16 (drop the <1.15 cap); add nkf + tsort, which
  Ruby 3.4+/4.0 removed from stdlib but CocoaPods' CFPropertyList needs.
- Podfile: build ZelloSDK's Swift deps (PhoneNumberKit, SnowplowTracker,
  CocoaLumberjack, PromisesSwift) with BUILD_LIBRARY_FOR_DISTRIBUTION so the
  prebuilt ZelloSDK can resolve their resilient symbols at launch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Firebase was declared but never used in the example: no JS import, no AppDelegate
configuration, no GoogleService-Info.plist, and the NotificationServiceExtension
doesn't reference it. Removing it trims the dependency surface.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a ZELLO_USE_SPM=1 opt-in to the podspec: when set, ZelloSDK is pulled via
Swift Package Manager (github.com/zelloptt/ios-mobile-sdk, product ZelloSDKUmbrella,
up-to-next-major from 2.0.0) using RN's spm_dependency helper, instead of the
CocoaPods 'pod ZelloSDK'. CocoaPods stays the default.

Full CocoaPods removal isn't possible on RN 0.86 (RN itself still requires
CocoaPods; SPM-only is an unshipped RN RFC, react-native-community/discussions-and-proposals#994),
so this mirrors sentry-react-native's SENTRY_USE_SPM approach: SPM for the native
SDK, CocoaPods for the RN layer.

Verified: ZELLO_USE_SPM=1 pod install + xcodebuild resolves ZelloSDK 2.0.5 from SPM
and the example builds, launches, and the SDK initializes - with no resilient-symbol
dyld workaround needed (SPM binaries are prebuilt resiliently).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- README: New Architecture + Node prerequisites; Turbo Native Module intro;
  native ZelloSDK via CocoaPods (default) or SPM (ZELLO_USE_SPM=1, Sentry-style);
  the required BUILD_LIBRARY_FOR_DISTRIBUTION post_install for the CocoaPods path
  on Xcode 16/26+; and why full CocoaPods removal isn't possible on RN 0.86 yet.
- CHANGELOG: 3.0.0 entry (New Arch breaking change, SPM opt-in).
- Bump version 2.0.1 -> 3.0.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rboModule

- Extend the generated NativeZelloSdkSpec; drop @ReactMethod and the getName override.
- Unify signatures to the shared codegen spec: configure(ReadableMap), selectContact
  (was setSelectedContact), getHistoryImageData (was getImageDataForHistoryImageMessage),
  split connectGroupConversation/disconnectGroupConversation; getHistory and
  getHistoryImageData resolve a Promise instead of invoking a Callback.
- JS getSdk(): on Android the NativeZelloSdk TurboModule owns the Zello delegate;
  drop the now-stale ZelloAndroidSdkModule NativeModules reference.
- Update the manual Hilt ReactPackage (README + example) to BaseReactPackage with a
  ReactModuleInfoProvider (isTurboModule = true).
- eslintIgnore: skip build/, generated/, Pods/ dirs (SPM checkouts were being linted).

Not built locally (no Android SDK/JDK) - to be verified in CI. connectGroupConversation
assumes the Android SDK's connectChannel accepts a ZelloGroupConversation (flagged in code).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Trigger on master (was main — CI never ran on this repo's default branch).
- build-ios: matrix over [cocoapods, spm] to verify both native-ZelloSDK install
  paths; install pods via bundle so the updated Gemfile (CocoaPods 1.16 + nkf/tsort)
  is honored, with RCT_NEW_ARCH_ENABLED=1; ZELLO_USE_SPM=1 for the spm variant.
- Add jest unit tests for the binary-search/comparator helpers (the test job had
  zero tests and was failing).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI surfaced these (Android can't be built locally — no SDK/JDK here):
- settings.gradle: the removed native_modules.gradle apply -> com.facebook.react.settings
  plugin + autolinkLibrariesFromCommand().
- app/build.gradle: drop applyNativeModulesAppBuildGradle; use autolinkLibrariesWithApp()
  inside the react {} block.
- MainApplication: SoLoader.init(this, OpenSourceMergedSoMapping) (the boolean overload is
  gone in RN 0.76+).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Hilt Gradle plugin was bumped to 2.56.2 (Kotlin 2.1.20 compat) but the example
app still pinned hilt-android / hilt-android-compiler 2.51. Dagger requires the
plugin and runtime libs to match, so the build would fail. Bumped both to 2.56.2.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RN 0.86 requires Xcode >= 16.1; the macos-14 runner ships 15.4, which made
use_react_native! abort with 'Please upgrade XCode'. macos-15 defaults to Xcode 16.x.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
compileDebugKotlin couldn't resolve NativeZelloSdkSpec because the library's
build.gradle was still the module-legacy structure. Add the module-new pieces:
- sourceSets generated/java + generated/jni so the generated spec compiles
- react { jsRootDir, libraryName = NativeZelloSdk, codegenJavaPackageName } so the
  RN Gradle plugin generates the library codegen into that location.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The library uses kapt (Hilt); the RN Gradle plugin adds build/generated/source/codegen/java
via finalizeDsl, which the Kotlin/kapt compile doesn't reliably pick up, leaving
NativeZelloSdkSpec unresolved. Register the codegen output dir on the main source set
explicitly (replacing the wrong generated/java path). The other Kotlin libs (screens,
safe-area-context) compile their codegen fine because they don't use kapt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…piles

The library's only @Inject was on ZelloAndroidSdkModule, which the host app
constructs manually (ZelloAndroidSdkPackage) — Hilt never processed it, so kapt was
dead weight. With kapt enabled, the generated NativeZelloSdkSpec wasn't visible to
kaptDebugKotlin/compileDebugKotlin, failing the build. Removing the Hilt plugin, kapt,
the Hilt deps, and the vestigial @Inject lets the codegen spec compile like the other
kapt-free Kotlin libs (screens, safe-area-context). The example app keeps Hilt (where
Zello is actually injected and passed to the package).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rxmichael and others added 4 commits June 16, 2026 23:12
…osdk

The gradle plugin passes --javaPackageName com.zellosdk (from
codegenConfig.android.javaPackageName), so RN generates the TurboModule spec as
com.zellosdk.NativeZelloSdkSpec, not com.facebook.fbreact.specs.NativeZelloSdkSpec.
Verified by running generate-specs-cli locally with that flag. Since the module is
already in package com.zellosdk, the spec is same-package and needs no import; the
old import was the real 'Unresolved reference NativeZelloSdkSpec' cause (kapt was a
red herring). All 29 override signatures match the generated abstract methods.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The example app linked com.zello:sdk:1.0.4, whose POM declares hilt-android:2.52
(pre-2.55, so it never emits Dagger's LazyClassKey helpers). The app was on Hilt
2.56.2, which generates SingletonC code importing *_LazyMapKey classes that don't
exist in the AAR -> :app:hiltJavaCompileDebug failed with 78 'cannot find symbol'
errors. Pinned the app + gradle-plugin classpath to 2.52 to match the AAR exactly.
(The library itself no longer uses Hilt, so it no longer constrains this version.)
Verified the AAR's Hilt version by fetching its POM from the S3 maven.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hilt 2.52 matched the com.zello:sdk AAR but crashed :app:kaptDebugKotlin under
Kotlin 2.1.20 (2.52 predates Kotlin 2.1). 2.54 is the newest release before
Dagger's LazyClassKey became the default (2.55), so it both runs cleanly under
Kotlin-2.1 kapt and avoids the _LazyMapKey references the pre-2.55 AAR lacks.
Also set kapt.verbose=true so any remaining annotation-processor error surfaces
in the CI log instead of a generic worker failure.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Zello SDK

The com.zello AARs are built with Dagger 2.52, whose @LazyClassKey impl predates
the per-binding *_LazyMapKey proxy classes. The example app must use Dagger >= 2.54
(RN 0.86 forces Kotlin 2.1.20; Dagger 2.52 crashes kapt under it), and >= 2.53
consumes the SDK's @LazyClassKey ViewModel bindings by referencing those proxies
from DaggerMainApplication_HiltComponents_SingletonC -> :app:hiltJavaCompileDebug
failed with 78 'cannot find symbol ... _LazyMapKey' errors.

Generate the 78 missing keeper classes (39 ViewModels x BindsModule_Binds +
KeyModule_Provide), matching Dagger's LazyMapKeyProxyGenerator output, by scanning
the SDK AARs for *_HiltModules classes. Workaround for a stale prebuilt SDK; remove
once the Zello Android SDK ships a Dagger >= 2.53 build (which emits these itself).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread .github/workflows/ci.yml
push:
branches:
- main
- master

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.

@zello-amiran looks like we did not migrated master to main although main referenced ?
cc: @bcorralejo-zptt

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This repo still uses master

Comment thread .github/workflows/ci.yml

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.

@rxmichael can we run this in our CI/CD environment to make sure it is going to work?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This has CI jobs for all three variants (see checks)

Comment thread android/build.gradle

apply plugin: "com.android.library"
apply plugin: "kotlin-android"
apply plugin: 'com.google.dagger.hilt.android'

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.

are we sure we are okay removing hilt?
(it was a requirnment in the past)

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.

generally wise I think it's correct to remove hilt from library dependencies list IMO

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.

is the idea to to have these classes instead of hilt?

Let's maybe leave hilt in the app rather then add generated shims?
@zello-eugene @padgrayson91 what do you think?

Comment thread README.md
#### Linking

Since the Zello Android SDK requires Hilt, and we must inject the `Zello` instance into the `ReactPackage`, the project does not work with autolinking.
Since the Zello Android SDK requires Hilt, and we must inject the `Zello` instance into the package, the project does not work with autolinking.

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.

looks like we did remove hilt from deps?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The consumer app's Hilt (what the README shows — @HiltAndroidApp, @Inject lateinit var zello, ZelloAndroidSdkPackage @Inject constructor(zello)): still required, still accurate. The app must use Hilt because that's the only way the Zello Android SDK hands you a Zello, and the package can't be autolinked since it needs that instance.

// com.zello:sdk AAR (built with Hilt 2.52), and 2.52 itself crashes kapt
// under Kotlin 2.1.20. 2.54 satisfies both: Kotlin-2.1-compatible kapt and
// no LazyClassKey output.
implementation("com.google.dagger:hilt-android:2.54")

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.

Let's maybe leave hilt in the app rather then add generated shims?
@zello-eugene @padgrayson91 what do you think?

}

override fun getName() = "ZelloAndroidSdkModule"
// getName() is provided by NativeZelloSdkSpec (returns "NativeZelloSdk").

@adambailey- adambailey- Jun 23, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is it safe to change the name?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

A New Arch TurboModule is defined by one codegen spec shared by both platforms, so it can't keep two different names — it needs a single platform-neutral one. That's why everything now resolves to NativeZelloSdk (Native* is the RN spec-file naming convention; the JS does getEnforcing('NativeZelloSdk') once, no branching).

// getName() is provided by NativeZelloSdkSpec (returns "NativeZelloSdk").

@ReactMethod fun configure(enableOfflineMessagePushNotifications: Boolean, enableForegroundService: Boolean) {
override fun configure(config: ReadableMap) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is this mandatory? It's significantly worse for readability and type clarify on what the options are

@ReactMethod fun startVoiceMessage(name: String, type: String) {
val contact = contactFrom(name, type) ?: return
override fun connectGroupConversation(name: String) {
// NOTE: confirm against the Android SDK that connectChannel accepts a

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We need to confirm this before merge. This also looks like new functionality which is odd for this PR


private let zello = Zello.shared

@objc public func configure(_ config: NSDictionary) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

An untyped arbitrary dictionary isn't great

@adambailey-

Copy link
Copy Markdown
Member

@rxmichael we need to target develop as the base branch, not master. Part of the release process reconciles this. We can merge anything into develop which is the benefit, we need master to work at all times but develop can be broken

rxmichael and others added 3 commits July 6, 2026 14:45
…ectChannel

Verified against com.zello:sdk:1.0.4 bytecode: ZelloGroupConversation extends
ZelloChannel and Zello.connectChannel/disconnectChannel take a ZelloChannel, so
passing a group conversation is a valid upcast. Resolves the prior TODO note.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The TurboModule boundary stays NSDictionary (the codegen spec uses UnsafeObject
because configure() is platform-specific and iOS only reads the 'ios' slice), but
the untyped key lookups are now centralized in a typed private Config struct so the
method body is type-safe and the payload-shape assumptions live in one place.
Behavior is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Confirmed against the ZelloSDK.xcframework swiftinterface: Zello.configuration is a
settable property and there is no configure() method — configuration is applied by
assignment. Master (and the migrated code) built a ZelloConfiguration with the
appGroup and pushNotificationEnvironment but never assigned it, so those settings
were silently ignored on iOS (push env always defaulted to .production, app group
never set). Assign zello.configuration so configure() takes effect.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rxmichael rxmichael changed the base branch from master to develop July 6, 2026 20:51
rxmichael and others added 4 commits July 7, 2026 12:15
The root npm lockfile was stale from before the migration (pinned react-native
0.74.5 / react 18.2.0). Regenerated with 'npm install --package-lock-only' so it
matches the current package.json and yarn.lock resolution: react-native 0.86.0,
react 19.2.3, @react-native/jest-preset 0.86.0, no 0.74.x references. The example
workspace's SDK dep is recorded as file:.. (npm's local-symlink form; the
package.json keeps yarn's link:.. and is unchanged).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Podfile.lock was committed stale at 2.0.1 while the podspec is 3.0.0, so
:app:CheckPodsManifest failed the iOS build with 'sandbox not in sync'. Updated the
lock to match the installed Pods sandbox (Manifest.lock, 3.0.0). Verified: the
example app builds and launches on the iOS simulator afterward.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The create/add-users dialogs used react-native-paper's adaptive Checkbox, which
renders Checkbox.IOS on iOS -- that variant shows only a checkmark when checked and
nothing (no box outline) when unchecked, so the rows looked empty on the simulator.
Use Checkbox.Android explicitly, which draws a visible box in both states on every
platform.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
In the create/add-users group-conversation dialogs the user row is a
space-between flex row; a long displayName grew unbounded and pushed the checkbox
off the right edge. Cap userName at width: '70%' so the checkbox always has room.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@rxmichael rxmichael merged commit 2c0ec3f into develop Jul 7, 2026
1 check passed
@rxmichael rxmichael deleted the michael/feat/turbomudle branch July 7, 2026 19:19
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