Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e5644e9
Remove reanimated v3/v4 split; enable new architecture on Android
peachbits Jun 25, 2026
b5f590e
Upgrade to React Native 0.86 and Expo SDK 57
peachbits Jul 3, 2026
0cd283a
Android: build under React Native 0.86 with the new architecture
peachbits Jun 29, 2026
5b1a4a2
iOS: build and run under React Native 0.86 / Expo SDK 57 / Xcode 26
peachbits Jun 29, 2026
600e74c
Android: fix Fabric crash on text inputs (fontSize 0)
peachbits Jul 10, 2026
cd5102d
Restore ShadowTree commit-exhaustion protection
peachbits Jul 3, 2026
0303acc
Upgrade reanimated to 4.5.3 and keyboard-controller to 1.22.2
peachbits Jul 25, 2026
83494b1
Android: enable ShadowTree commit-exhaustion protection at runtime
peachbits Jul 25, 2026
3976b79
Fix drawer overlay on Android versions that cannot animate it
peachbits Jul 25, 2026
171bdf3
Fix invisible and washed-out blur backgrounds on older Android devices
peachbits Jul 25, 2026
8aaa43e
Wait for the core context before auto-logging in
peachbits Jul 25, 2026
48aa4d9
Android: turn off Fabric view recycling
peachbits Jul 26, 2026
20a4aa0
Keep shrink-to-fit text above its minimum size under the new architec…
peachbits Jul 27, 2026
3747995
Keep modals above the keyboard on Android
peachbits Jul 27, 2026
7f5be35
Fix amount field spacing and clipping on Android
peachbits Jul 27, 2026
b7e61b2
Stop the amount field jumping as you type
peachbits Jul 27, 2026
836af1f
Fix expo-modules-jsi under newer Swift compilers
peachbits Aug 31, 2026
216f7a7
Patch expo-modules-core for stricter Swift concurrency checks
peachbits Aug 31, 2026
5892a97
Drop two unused dependencies
peachbits Aug 10, 2026
7a0a4ce
Render gradients with expo-linear-gradient
peachbits Aug 10, 2026
23105bf
Install one copy of airship and patina
peachbits Aug 11, 2026
3efc85d
Scroll around the keyboard with keyboard-controller
peachbits Aug 12, 2026
ba24007
Drop the BlurView global nothing reads anymore
peachbits Aug 31, 2026
51394c5
Blur modals and chrome again on Android 12+
peachbits Aug 31, 2026
b1a8a34
Drop notifications below the Android status bar
peachbits Aug 31, 2026
b4fae5d
Upgrade react-native-performance to 6.0.0
peachbits Sep 1, 2026
7459460
Upgrade react-native-sound to 0.13 and haptic-feedback to 3.0
peachbits Sep 1, 2026
792b029
Add changelog entries
peachbits Aug 31, 2026
be4cb34
Start disabled text inputs in their disabled look
peachbits Sep 1, 2026
a3864df
Sync the login-ui patch with the lib fixes
peachbits Sep 3, 2026
81c52d0
Fix the drawer overlay collapsing on React Native 0.86
peachbits Sep 7, 2026
b3f3cca
Sync the login-ui patch with the absolute-fill fix
peachbits Sep 7, 2026
bb41a87
Blur with expo-blur on iOS too
peachbits Sep 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
# edge-react-gui

## Unreleased (develop)
- fixed: The side menu's dimming overlay works again on both platforms. React Native 0.86 removed the `StyleSheet.absoluteFillObject` the drawer's overlay spreads, which collapsed it to nothing, so tapping outside the menu no longer closed it.
- changed: Blur on iOS now uses `expo-blur`, the same backend as Android 12+, so `rn-id-blurview` (an old-architecture view manager with no new-architecture support) is no longer a dependency.
- fixed: Text inputs mounted in the disabled state (such as the spending-limit amount) no longer flash their enabled look before dimming when a scene appears.
- fixed: Received-transaction and error dropdowns no longer slide in underneath the Android status bar on edge-to-edge devices.
- fixed: The header, scene footer, tab bar, keyboard-avoiding buttons, and notification cards blur the scene behind them again on Android 12 and above, sampling the focused scene's content. Below Android 12 they keep their solid backgrounds.
- fixed: See-through modal sheets on Android under the new architecture. Modals blur the screen behind them again on Android 12 and above via a new blur backend (the old one snapshots the window in a way the new architecture renders as empty), and use a solid background color below Android 12, where no blur implementation can render.

- changed: Draw gradients with expo-linear-gradient and scroll around the keyboard with react-native-keyboard-controller, replacing two libraries that rendered through the new architecture's legacy compatibility layers (react-native-linear-gradient and the unmaintained react-native-keyboard-aware-scroll-view).
- changed: The feedback survey now uses the same keyboard offset on both platforms, replacing a per-platform workaround the old scroll library required.
- fixed: The app no longer installs two copies of react-native-airship and react-native-patina (one nested under edge-login-ui-rn).

- changed: Upgrade react-native-sound to 0.13.0 and react-native-haptic-feedback to 3.0.0, both now codegen-native under the new architecture.
- changed: Upgrade react-native-performance to 6.0.0, fixing new-architecture detection and an Android event-emitter race.
- changed: Upgrade to React Native 0.86, Expo SDK 57, and the new architecture on both platforms. On Android this substantially improves scrolling performance: in release-build benchmarks, dropped frames during wallet-list scrolling fell from 7.3% to 2.5%, the worst-case frame rate rose from 33 to 48 fps, and peak CPU fell 38%, at the cost of higher memory use.
- fixed: Labels that shrink to fit stop at their minimum size again. The new architecture ignores `minimumFontScale` on both platforms and shrank long labels as far as 4 points; the app now also passes the absolute floor the renderers do honor, via a small `react-native` patch, so labels shrink no further than before.
- changed: Android 11 and below now show solid backgrounds where blur effects used to be. Those Android versions cannot render blur under the new architecture, which painted a gray wash over the content instead.
- fixed: Modals no longer sit behind the keyboard on Android, hiding their bottom buttons.
- fixed: The amount field no longer clips its leading digits or shifts sideways while typing.
- fixed: Tapping outside the side menu closes it again on Android versions that cannot animate the overlay.
- fixed: Screen readers no longer announce the amount field's hidden sizing text, which read as the amount with a stray trailing zero.

- changed: Standardize wallet list automation test IDs to use period separators.
- changed: Lock the send confirmation slider for the rest of the scene once a broadcast has been attempted, whether the broadcast reported success or failure, and replace the generic failure card with a message that the transaction may have gone through, pointing at the block explorer or confirmation email before trying again.
Expand Down
8 changes: 8 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ android {
compileSdk rootProject.ext.compileSdkVersion

namespace "co.edgesecure.app"

lint {
// Release lint (lintVital) OOMs on this large project and isn't needed
// for benchmark/release APKs; CI runs lint separately.
checkReleaseBuilds false
abortOnError false
}

defaultConfig {
applicationId "co.edgesecure.app"
minSdkVersion rootProject.ext.minSdkVersion
Expand Down
66 changes: 48 additions & 18 deletions android/app/src/main/java/co/edgesecure/app/MainApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlagsProvider
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.modules.i18nmanager.I18nUtil
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader
import expo.modules.ApplicationLifecycleDispatcher.onApplicationCreate
import expo.modules.ApplicationLifecycleDispatcher.onConfigurationChanged
import expo.modules.ReactNativeHostWrapper
import io.sentry.Hint
import io.sentry.SentryEvent
import io.sentry.SentryLevel
Expand All @@ -27,26 +29,23 @@ class MainApplication :
Application(),
ReactApplication {
override val reactNativeHost: ReactNativeHost =
ReactNativeHostWrapper(
this,
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
// Packages that cannot be autolinked yet can be added manually here, for
// example:
// packages.add(new MyReactNativePackage());
val packages = PackageList(this).packages
packages.add(EdgeAttestationPackage())
return packages
}
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
// Packages that cannot be autolinked yet can be added manually here, for
// example:
// packages.add(new MyReactNativePackage());
val packages = PackageList(this).packages
packages.add(EdgeAttestationPackage())
return packages
}

override fun getJSMainModuleName(): String = "index"
override fun getJSMainModuleName(): String = "index"

override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
},
)
override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}

override val reactHost: ReactHost
get() = getDefaultReactHost(applicationContext, reactNativeHost)
Expand Down Expand Up @@ -109,6 +108,37 @@ class MainApplication :
// If you opted-in for the New Architecture, we load the native entry point for this
// app.
load()

// load() consumed the process's single feature-flag override with React
// Native's stable defaults. Replace it with those same defaults plus the
// ShadowTree commit-exhaustion protection, which React Native ships
// default-off: without it, a runaway commit loop aborts the app in
// native code (ShadowTree.cpp: "assertion failed (attempts < 1024)").
// Android loads the RN core prebuilt, so the default cannot be patched
// in source like on iOS. Resetting here is safe because no React
// runtime exists yet.
ReactNativeFeatureFlags.dangerouslyReset()
ReactNativeFeatureFlags.override(
object :
ReactNativeFeatureFlagsProvider by ReactNativeFeatureFlagsOverrides_RNOSS_Stable_Android() {
override fun preventShadowTreeCommitExhaustion(): Boolean = true

// View recycling only runs under the new architecture, so enabling
// it turned these on for the first time. Recycled views arrive
// carrying visual properties from their previous use: buttons stay
// dimmed after becoming enabled, and labels render at a stale font
// size. Keep them off, matching how the app rendered before the
// architecture switch.
// The master recycling switch defaults off in 0.86.0, but pin it so
// a future point release cannot flip it on and silently activate
// the image recycler (which defaults on under the master switch):
override fun enableViewRecycling(): Boolean = false

override fun enableViewRecyclingForText(): Boolean = false

override fun enableViewRecyclingForView(): Boolean = false
}
)
}
onApplicationCreate(this)
}
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
buildscript {
ext {
buildToolsVersion = "35.0.0"
buildToolsVersion = "36.1.0"
minSdkVersion = 28 // Edge modified from 21
compileSdkVersion = 36
targetSdkVersion = 36
Expand Down
4 changes: 2 additions & 2 deletions android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m
org.gradle.jvmargs=-Xmx6g -XX:MaxMetaspaceSize=1g

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
Expand All @@ -37,7 +37,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false
newArchEnabled=true

# Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead.
Expand Down
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
44 changes: 37 additions & 7 deletions android/settings.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,39 @@
pluginManagement { includeBuild("../node_modules/@react-native/gradle-plugin") }
plugins { id("com.facebook.react.settings") }
extensions.configure(com.facebook.react.ReactSettingsExtension){ ex -> ex.autolinkLibrariesFromCommand() }
pluginManagement {
def reactNativeGradlePlugin = new File(
providers.exec {
workingDir(rootDir)
commandLine("node", "--print", "require.resolve('@react-native/gradle-plugin/package.json', { paths: [require.resolve('react-native/package.json')] })")
}.standardOutput.asText.get().trim()
).getParentFile().absolutePath
includeBuild(reactNativeGradlePlugin)

def expoPluginsPath = new File(
providers.exec {
workingDir(rootDir)
commandLine("node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })")
}.standardOutput.asText.get().trim(),
"../android/expo-gradle-plugin"
).absolutePath
includeBuild(expoPluginsPath)
}

plugins {
id("com.facebook.react.settings")
id("expo-autolinking-settings")
}

extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
if (System.getenv('EXPO_USE_COMMUNITY_AUTOLINKING') == '1') {
ex.autolinkLibrariesFromCommand()
} else {
ex.autolinkLibrariesFromCommand(expoAutolinking.rnConfigCommand)
}
}
expoAutolinking.useExpoModules()

rootProject.name = 'co.edgesecure.app'
include ':app'
includeBuild('../node_modules/@react-native/gradle-plugin')

apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle")
useExpoModules()
expoAutolinking.useExpoVersionCatalog()

include ':app'
includeBuild(expoAutolinking.reactNativeGradlePlugin)
9 changes: 2 additions & 7 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
module.exports = function (api) {
const isAndroid = api.caller(c => c.platform === 'android')

api.cache(true)
return {
presets: ['module:@react-native/babel-preset'],
plugins: [
isAndroid
? './node_modules/r3-hack/node_modules/react-native-reanimated/plugin'
: 'react-native-worklets/plugin'
]
plugins: ['react-native-worklets/plugin']
}
}
33 changes: 9 additions & 24 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export default [
'src/app.ts',
'src/components/buttons/ButtonsView.tsx',
'src/components/buttons/EdgeSwitch.tsx',
'src/components/buttons/IconButton.tsx',

'src/components/buttons/MinimalButton.tsx',
'src/components/buttons/ModalButtons.tsx',
'src/components/buttons/ReturnKeyTypeButton.tsx',
Expand All @@ -149,7 +149,7 @@ export default [

'src/components/cards/FiatAmountInputCard.tsx',
'src/components/cards/FiatExchangeDetailsCard.tsx',
'src/components/cards/HomeTileCard.tsx',

'src/components/cards/IconMessageCard.tsx',
'src/components/cards/LoanDetailsSummaryCard.tsx',
'src/components/cards/LoanSummaryCard.tsx',
Expand All @@ -167,9 +167,8 @@ export default [
'src/components/charts/SwipeChart.tsx',

'src/components/common/AnimatedNumber.tsx',
'src/components/common/BlurBackground.tsx',

'src/components/common/CrossFade.tsx',
'src/components/common/DotsBackground.tsx',

'src/components/common/ExpandableList.tsx',
'src/components/common/QrPeephole.tsx',
Expand All @@ -181,7 +180,7 @@ export default [
'src/components/FioAddress/FioActionSubmit.tsx',
'src/components/FioAddress/FioName.tsx',
'src/components/hoc/maybeComponent.tsx',
'src/components/hoc/styled.tsx',

'src/components/hoc/withExtendedTouchable.tsx',

'src/components/icons/FiatIcon.tsx',
Expand All @@ -207,7 +206,6 @@ export default [
'src/components/modals/FioExpiredModal.tsx',

'src/components/modals/FundAccountModal.tsx',
'src/components/modals/GradientFadeout.tsx',

'src/components/modals/InsufficientFeesModal.tsx',
'src/components/modals/ListModal.tsx',
Expand All @@ -233,7 +231,7 @@ export default [
'src/components/navigation/EdgeLogoHeader.tsx',
'src/components/navigation/FlashNotification.tsx',
'src/components/navigation/GuiPluginBackButton.tsx',
'src/components/navigation/HeaderBackground.tsx',

'src/components/navigation/HeaderTextButton.tsx',
'src/components/navigation/HeaderTitle.tsx',
'src/components/navigation/NavigationButton.tsx',
Expand All @@ -246,8 +244,6 @@ export default [
'src/components/progress-indicators/FullScreenLoader.tsx',
'src/components/progress-indicators/LoadingSplashScreen.tsx',

'src/components/progress-indicators/StepProgressBar.tsx',

'src/components/rows/CryptoFiatAmountRow.tsx',

'src/components/rows/EdgeRow.tsx',
Expand All @@ -256,9 +252,6 @@ export default [
'src/components/rows/SwapProviderRow.tsx',
'src/components/rows/TxCryptoAmountRow.tsx',

'src/components/scenes/ChangeMiningFeeScene.tsx',

'src/components/scenes/ConfirmScene.tsx',
'src/components/scenes/CreateWalletAccountSelectScene.tsx',
'src/components/scenes/CreateWalletAccountSetupScene.tsx',

Expand All @@ -283,15 +276,13 @@ export default [
'src/components/scenes/Fio/FioRequestListScene.tsx',
'src/components/scenes/Fio/FioSentRequestDetailsScene.tsx',
'src/components/scenes/Fio/FioStakingOverviewScene.tsx',
'src/components/scenes/FormScene.tsx',

'src/components/scenes/inputs/DigitInput.tsx',
'src/components/scenes/inputs/DigitInput/PinDots.tsx',
'src/components/scenes/LoadingScene.tsx',
'src/components/scenes/Loans/LoanCloseScene.tsx',

'src/components/scenes/Loans/LoanCreateScene.tsx',
'src/components/scenes/Loans/LoanDashboardScene.tsx',
'src/components/scenes/Loans/LoanDetailsScene.tsx',

'src/components/scenes/Loans/LoanManageScene.tsx',
'src/components/scenes/Loans/LoanStatusScene.tsx',

Expand All @@ -302,7 +293,6 @@ export default [

'src/components/scenes/PromotionSettingsScene.tsx',

'src/components/scenes/SpendingLimitsScene.tsx',
'src/components/scenes/Staking/EarnScene.tsx',

'src/components/scenes/SwapSettingsScene.tsx',
Expand All @@ -326,7 +316,6 @@ export default [
'src/components/services/NetworkActivity.ts',
'src/components/services/PasswordReminderService.ts',
'src/components/services/PermissionsManager.tsx',
'src/components/services/Providers.tsx',

'src/components/services/SortedWalletList.ts',
'src/components/services/StatusBarManager.tsx',
Expand All @@ -346,18 +335,15 @@ export default [
'src/components/text/TitleText.tsx',
'src/components/themed/Alert.tsx',

'src/components/themed/DividerLine.tsx',
'src/components/themed/EdgeProviderComponent.tsx',

'src/components/themed/ExplorerCard.tsx',
'src/components/themed/Fade.tsx',

'src/components/themed/FioRequestRow.tsx',

'src/components/themed/LineTextDivider.tsx',
'src/components/themed/MainButton.tsx',
'src/components/themed/ManageTokensRow.tsx',
'src/components/themed/MenuTabs.tsx',

'src/components/themed/ModalParts.tsx',
'src/components/themed/PinDots.tsx',

Expand All @@ -373,7 +359,6 @@ export default [
'src/components/themed/ThemedButtons.tsx',
'src/components/themed/Thermostat.tsx',
'src/components/themed/Title.tsx',
'src/components/themed/TransactionListComponents.tsx',

'src/components/themed/VectorIcon.tsx',
'src/components/themed/WalletList.tsx',
Expand Down Expand Up @@ -480,7 +465,7 @@ export default [
'src/styles/common/textStyles.tsx',
'src/styles/common/textStylesThemed.ts',
'src/types/reactRedux.ts',
'src/util/borrowUtils.ts',

'src/util/cleaners.ts',

'src/util/crypto.ts',
Expand Down
Loading
Loading