Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
4ebfe57
Remove reanimated v3/v4 split; enable new architecture on Android
peachbits Jun 25, 2026
7f84e1e
Upgrade to React Native 0.86 and Expo SDK 57
peachbits Jul 3, 2026
f7cfbff
Android: build under React Native 0.86 with the new architecture
peachbits Jun 29, 2026
245323a
iOS: build and run under React Native 0.86 / Expo SDK 57 / Xcode 26
peachbits Jun 29, 2026
454d83b
Android: fix Fabric crash on text inputs (fontSize 0)
peachbits Jul 10, 2026
71bf0bd
Restore ShadowTree commit-exhaustion protection
peachbits Jul 3, 2026
71bdaaa
Upgrade reanimated to 4.5.3 and keyboard-controller to 1.22.2
peachbits Jul 25, 2026
9b7b492
Android: enable ShadowTree commit-exhaustion protection at runtime
peachbits Jul 25, 2026
2ba6521
Fix drawer overlay on Android versions that cannot animate it
peachbits Jul 25, 2026
2a613ba
Fix invisible and washed-out blur backgrounds on older Android devices
peachbits Jul 25, 2026
f5bf411
Wait for the core context before auto-logging in
peachbits Jul 25, 2026
cf3efbc
Android: turn off Fabric view recycling
peachbits Jul 26, 2026
dea9375
Stop text shrinking itself illegibly small on Android
peachbits Jul 27, 2026
c1a36f6
Keep modals above the keyboard on Android
peachbits Jul 27, 2026
b0f7ca6
Fix amount field spacing and clipping on Android
peachbits Jul 27, 2026
c89e80b
Stop the amount field jumping as you type
peachbits Jul 27, 2026
afb85b9
Fix expo-modules-jsi under newer Swift compilers
peachbits Aug 31, 2026
374640f
Patch expo-modules-core for stricter Swift concurrency checks
peachbits Aug 31, 2026
5550444
Drop two unused dependencies
peachbits Aug 10, 2026
2438b09
Render gradients with expo-linear-gradient
peachbits Aug 10, 2026
597ae02
Install one copy of airship and patina
peachbits Aug 11, 2026
116b60e
Scroll around the keyboard with keyboard-controller
peachbits Aug 12, 2026
3556021
Drop the BlurView global nothing reads anymore
peachbits Aug 31, 2026
d42daf8
Blur modals and chrome again on Android 12+
peachbits Aug 31, 2026
1b339f6
Drop notifications below the Android status bar
peachbits Aug 31, 2026
ded5694
Upgrade react-native-performance to 6.0.0
peachbits Sep 1, 2026
5e30fe0
Upgrade react-native-sound to 0.13 and haptic-feedback to 3.0
peachbits Sep 1, 2026
5374f1f
Add changelog entries
peachbits Aug 31, 2026
5c1a48b
fixup! Blur modals and chrome again on Android 12+
peachbits Sep 1, 2026
adfaf93
Start disabled text inputs in their disabled look
peachbits Sep 1, 2026
60fb0b7
fixup! Upgrade to React Native 0.86 and Expo SDK 57
peachbits Sep 2, 2026
1216f70
fixup! Keep modals above the keyboard on Android
peachbits Sep 3, 2026
2fd4758
fixup! Android: fix Fabric crash on text inputs (fontSize 0)
peachbits Sep 3, 2026
a7ac2a8
fixup! Stop the amount field jumping as you type
peachbits Sep 3, 2026
c802615
fixup! Android: turn off Fabric view recycling
peachbits Sep 3, 2026
4d8bce9
fixup! Add changelog entries
peachbits Sep 3, 2026
224c2e7
Sync the login-ui patch with the lib fixes
peachbits Sep 3, 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
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
# edge-react-gui

## Unreleased (develop)
- 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, 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.
- changed: Long labels on Android now truncate with an ellipsis instead of shrinking to fit. The new renderer ignores the minimum text size, which could render labels illegibly small.
- 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.

## 4.51.0 (staging)

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 @@ -150,7 +150,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 @@ -168,9 +168,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 @@ -182,7 +181,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 @@ -208,7 +207,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 @@ -234,7 +232,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 @@ -247,8 +245,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 @@ -257,9 +253,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 @@ -284,15 +277,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 @@ -303,7 +294,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 @@ -327,7 +317,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 @@ -347,18 +336,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 @@ -374,7 +360,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 @@ -483,7 +468,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