Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased (develop)

- added: Home screen long-press shortcut to contact support
- added: Home screen long-press shortcut warning about data loss on uninstall
Copy link
Contributor

Choose a reason for hiding this comment

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

Warning: "Data loss" wording may be misleading.

The shortcut points to "Getting a new phone" and emphasizes 2FA and credentials, not funds or wallet data. "Data loss" could imply loss of crypto.

Suggestion:

- added: Home screen long-press shortcut warning about 2FA and credentials needed after uninstall


## 4.44.0 (staging)

- added: MAYAChain (CACAO) wallet support
Expand Down
3 changes: 3 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="wc" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>

<!-- To disable the activity lifecycle breadcrumbs integration -->
Expand Down
4 changes: 4 additions & 0 deletions android/app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
<resources>
<string name="app_name">Edge</string>
<string name="shortcut_contact_support_short">Contact Support</string>
<string name="shortcut_contact_support_long">Contact support for help from a live agent</string>
Copy link
Contributor

Choose a reason for hiding this comment

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

Warning: Inconsistent copy between platforms.

Platform Contact Support (long)
Android "Contact support for help from a live agent"
iOS "Get help from our live support agents"

Same feature with different wording can be confusing for localization and UX.

Recommendation: Pick one and use it on both platforms.

<string name="shortcut_do_not_uninstall_short">⚠️ Save 2FA First!</string>
<string name="shortcut_do_not_uninstall_long">⚠️ Login requires 2FA & credentials!</string>
Copy link
Contributor

Choose a reason for hiding this comment

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

Critical: Unescaped ampersand in XML.

In XML, & must be escaped as &amp;. An unescaped & can cause parse errors or unexpected behavior.

Fix:

<string name="shortcut_do_not_uninstall_long">⚠️ Login requires 2FA &amp; credentials!</string>

Comment on lines +5 to +6
Copy link
Contributor

Choose a reason for hiding this comment

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

Warning: Double emoji on Android vs single on iOS.

  • Android short: "⚠️ Save 2FA First!"
  • Android long: "⚠️ Login requires 2FA & credentials!"
  • iOS title: "⚠️ Save 2FA First!"
  • iOS subtitle: "Login requires 2FA & credentials!" (no emoji)

Android uses ⚠️ in both labels; iOS only in the title. The double emoji on Android can feel redundant.

Recommendation: Remove ⚠️ from the Android long label to match iOS.

</resources>
23 changes: 23 additions & 0 deletions android/app/src/main/res/xml/shortcuts.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
Copy link
Contributor

Choose a reason for hiding this comment

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

Warning: Shortcut order differs between platforms.

  • iOS: 2FA warning first, Contact Support second
  • Android: Contact Support first, 2FA warning second

If the order is intentional for platform UX, add a comment explaining the rationale. Otherwise, align for consistency.

android:shortcutId="contact_support"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: Both Android shortcuts use the same app launcher icon (@mipmap/ic_launcher), making them visually identical.

iOS uses distinct SF Symbols (nosign and message.fill) for each shortcut. Consider using different icons for Android too to improve shortcut recognition and UX.

android:shortcutShortLabel="@string/shortcut_contact_support_short"
android:shortcutLongLabel="@string/shortcut_contact_support_long">
<intent
android:action="android.intent.action.VIEW"
android:data="https://support.edge.app/hc/en-us?chat=open" />
Copy link
Contributor

Choose a reason for hiding this comment

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

Critical: Android shortcuts will not work — https URLs are not opened in the browser.

The iOS implementation in AppDelegate.swift intercepts https/http URLs and opens them directly in Safari:

if url.scheme == "https" || url.scheme == "http" {
  UIApplication.shared.open(url)
  return true
}

However, Android has no equivalent native handling. The intent sends the URL to MainActivity, which passes it through React Native's LinkingparseDeepLinklaunchDeepLink. The 'other' case tries to parse it as a wallet URI, fails, and shows "No wallet for this URI" toast.

Recommended fix (consistent with iOS): Add native Android handling in MainActivity to open https/http shortcut URLs in the browser before they reach React Native. This matches the iOS pattern where https URLs bypass parseDeepLink.


Alternative design consideration: If the preference is to have parseDeepLink be the central handler for all intent URIs, the fix would instead be:

  1. Update the 'other' case in DeepLinkingActions.tsx to open unrecognized https URLs in the browser as a fallback (similar to linkReferralWithCurrencies which already does if (parsed.type === 'other') await Linking.openURL(uri))
  2. Update iOS AppDelegate.swift to pass https URLs through RCTLinkingManager instead of opening them directly

This would centralize URL handling logic in one place (the deep link infrastructure) rather than having platform-specific native handling.

</shortcut>
<shortcut
android:shortcutId="do_not_uninstall"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:shortcutShortLabel="@string/shortcut_do_not_uninstall_short"
android:shortcutLongLabel="@string/shortcut_do_not_uninstall_long">
<intent
android:action="android.intent.action.VIEW"
android:data="https://support.edge.app/hc/en-us/articles/24469866252443-Getting-a-new-phone" />
</shortcut>
</shortcuts>
31 changes: 31 additions & 0 deletions ios/edge/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var securityView: UIView?
private var pendingShortcutItem: UIApplicationShortcutItem?
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: Consider adding a brief comment explaining why shortcut handling is deferred.

The pattern of storing pendingShortcutItem and handling it after React Native setup is useful but not immediately obvious. A comment like:

// Shortcut actions are deferred until React Native is fully initialized
private var pendingShortcutItem: UIApplicationShortcutItem?

would clarify the intent for future readers.


var reactNativeDelegate: ReactNativeDelegate?
var reactNativeFactory: RCTReactNativeFactory?
Expand Down Expand Up @@ -49,6 +50,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
if let shortcutItem = launchOptions?[.shortcutItem] as? UIApplicationShortcutItem {
pendingShortcutItem = shortcutItem
}

// Initialize SDK's:
initializeSentry()
FirebaseApp.configure()
Expand All @@ -72,9 +77,35 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
launchOptions: launchOptions
)

if let shortcutItem = pendingShortcutItem {
_ = handleShortcutItem(shortcutItem)
pendingShortcutItem = nil
}

return true
}

func application(
_ application: UIApplication,
performActionFor shortcutItem: UIApplicationShortcutItem,
completionHandler: @escaping (Bool) -> Void
) {
let handled = handleShortcutItem(shortcutItem)
completionHandler(handled)
}

private func handleShortcutItem(_ shortcutItem: UIApplicationShortcutItem) -> Bool {
guard let url = URL(string: shortcutItem.type) else { return false }

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: UIApplication.shared.open has a completion handler that could help with debugging or analytics.

UIApplication.shared.open(url, options: [:]) { success in
  if !success {
    // Log or handle failure
  }
}

Not critical, but could be useful for future troubleshooting.

// Open https/http URLs in the default browser, otherwise handle as deep link
if url.scheme == "https" || url.scheme == "http" {
UIApplication.shared.open(url)
return true
}

return RCTLinkingManager.application(UIApplication.shared, open: url, options: [:])
}

/**
* Periodic background fetch logic.
* Edge addition.
Expand Down
23 changes: 23 additions & 0 deletions ios/edge/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,29 @@
</array>
<key>CFBundleVersion</key>
<string>99999999</string>
<key>UIApplicationShortcutItems</key>
Copy link
Contributor

Choose a reason for hiding this comment

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

Localization: These shortcut strings are hardcoded in English only.

The app supports 13 locales via React Native (src/locales/strings/*.json), but these native shortcuts won't be translated.

Recommendation: Use InfoPlist.strings for localization:

  1. Create ios/edge/en.lproj/InfoPlist.strings:
SHORTCUT_UNINSTALL_TITLE = "⚠️ Save 2FA First!";
SHORTCUT_SUPPORT_TITLE = "Contact Support";
  1. Create locale-specific .lproj folders (e.g., es.lproj, de.lproj) with translated strings.

  2. Update Info.plist to use the keys instead of hardcoded strings.

Similarly for Android, add values-es/strings.xml, values-de/strings.xml, etc.

This could be deferred to a follow-up PR, but should at least be documented as a known limitation.

<array>
<dict>
<key>UIApplicationShortcutItemTitle</key>
<string>⚠️ Save 2FA First!</string>
<key>UIApplicationShortcutItemSubtitle</key>
<string>Login requires 2FA & credentials!</string>
<key>UIApplicationShortcutItemIconSymbolName</key>
<string>nosign</string>
<key>UIApplicationShortcutItemType</key>
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion: UIApplicationShortcutItemType is typically an identifier (e.g. com.edge.app.contact_support), not a full URL.

Storing URLs there works, but it mixes identity with data. Consider using a type like contact_support and passing the URL via userInfo for clearer separation. The handleShortcutItem function would then switch on the type and look up the URL.

<string>https://support.edge.app/hc/en-us/articles/24469866252443-Getting-a-new-phone</string>
</dict>
<dict>
<key>UIApplicationShortcutItemTitle</key>
<string>Contact Support</string>
<key>UIApplicationShortcutItemSubtitle</key>
<string>Get help from our live support agents</string>
<key>UIApplicationShortcutItemIconSymbolName</key>
<string>message.fill</string>
<key>UIApplicationShortcutItemType</key>
<string>https://support.edge.app/hc/en-us?chat=open</string>
</dict>
</array>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>https</string>
Expand Down
Loading