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
28 changes: 22 additions & 6 deletions App.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,41 @@
import { NavigationContainer } from '@react-navigation/native';
import React from 'react';
import { useColorScheme } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import { SizeClassProvider } from './components/Context/SizeClassProvider';
import { SettingsProvider } from './components/Context/SettingsProvider';
import { BlueDefaultTheme } from './components/themes';
import { BlueCurrentTheme, BlueDarkTheme, BlueDefaultTheme } from './components/themes';
import MasterView from './navigation/MasterView';
import { navigationRef } from './NavigationService';
import { useLogger } from '@react-navigation/devtools';
import { StorageProvider } from './components/Context/StorageProvider';
import { initializeIndexer } from './blue_modules/SilentPaymentIndexer';
import CustomAlert, { CustomAlertHandle } from './components/CustomAlert';
import { setCustomAlertRef } from './components/Alert';

const App = () => {
initializeIndexer({
baseUrl: 'https://cushionlike-isabel-retrievable.ngrok-free.dev/',
timeout: 100000, // 100 seconds for blockchain scanning operations (increased for slower connections)
});
const customAlertRef = React.useRef<CustomAlertHandle>(null);

React.useEffect(() => {
setCustomAlertRef(customAlertRef.current);
initializeIndexer({
baseUrl: 'https://cushionlike-isabel-retrievable.ngrok-free.dev/',
timeout: 100000, // 100 seconds for blockchain scanning operations (increased for slower connections)
});
return () => setCustomAlertRef(null);
}, []);
Comment on lines +17 to +26
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.

i dont like the approach of using useRef inside a useEffect

Comment on lines +17 to +26
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.

Suggested change
const customAlertRef = React.useRef<CustomAlertHandle>(null);
React.useEffect(() => {
setCustomAlertRef(customAlertRef.current);
initializeIndexer({
baseUrl: 'https://cushionlike-isabel-retrievable.ngrok-free.dev/',
timeout: 100000, // 100 seconds for blockchain scanning operations (increased for slower connections)
});
return () => setCustomAlertRef(null);
}, []);
const handleCustomAlertRef = React.useCallback((ref: CustomAlertHandle | null) => {
setCustomAlertRef(ref);
}, []);
React.useEffect(() => {
initializeIndexer({
baseUrl: 'https://cushionlike-isabel-retrievable.ngrok-free.dev/',
timeout: 100000, // 100 seconds for blockchain scanning operations (increased for slower connections)
});
}, []);


const colorScheme = useColorScheme();

React.useEffect(() => {
BlueCurrentTheme.updateColorScheme();
}, [colorScheme]);
Comment on lines +30 to +32
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.

dead code


useLogger(navigationRef);

return (
<SizeClassProvider>
<NavigationContainer ref={navigationRef} theme={BlueDefaultTheme}>
<NavigationContainer ref={navigationRef} theme={colorScheme === 'dark' ? BlueDarkTheme : BlueDefaultTheme}>
<SafeAreaProvider>
Comment thread
chaitika marked this conversation as resolved.
<StorageProvider>
<SettingsProvider>
Expand All @@ -29,6 +44,7 @@ const App = () => {
</StorageProvider>
</SafeAreaProvider>
</NavigationContainer>
<CustomAlert ref={customAlertRef} />
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.

this should be mounted once at the app root level and can work globally across screens, please move this to just below <MasterView />

</SizeClassProvider>
);
};
Expand Down
9 changes: 9 additions & 0 deletions components/Alert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ import { Alert as RNAlert, Platform, ToastAndroid, AlertButton, AlertOptions } f
import triggerHapticFeedback, { HapticFeedbackTypes } from '../blue_modules/hapticFeedback';
import loc from '../loc';
import { navigationRef } from '../NavigationService';
import type { CustomAlertHandle } from './CustomAlert';

export enum AlertType {
Alert,
Toast,
}

let customAlertRef: CustomAlertHandle | null = null;

export function setCustomAlertRef(ref: CustomAlertHandle | null): void {
customAlertRef = ref;
}

const presentAlert = (() => {
let lastAlertParams: {
title?: string;
Expand All @@ -25,6 +32,8 @@ const presentAlert = (() => {
const showAlert = (title: string | undefined, message: string, buttons: AlertButton[], options: AlertOptions) => {
if (Platform.OS === 'ios' && navigationRef.isReady()) {
RNAlert.alert(title ?? message, title && message ? message : undefined, buttons, options);
} else if (Platform.OS === 'android' && customAlertRef) {
customAlertRef.show(title ?? message, title && message ? message : undefined, buttons, options);
} else {
RNAlert.alert(title ?? '', message, buttons, options);
}
Expand Down
119 changes: 119 additions & 0 deletions components/CustomAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React, { useCallback, useImperativeHandle, useState, forwardRef } from 'react';
import { Modal, View, Text, TouchableOpacity, StyleSheet, AlertButton, AlertOptions, Appearance } from 'react-native';
import { BlueDefaultTheme, BlueDarkTheme } from './themes';

export interface CustomAlertHandle {
show: (title: string | undefined, message: string | undefined, buttons: AlertButton[], options: AlertOptions) => void;
}

const CustomAlert = forwardRef<CustomAlertHandle>((_, ref) => {
const [visible, setVisible] = useState(false);
const [title, setTitle] = useState<string | undefined>();
const [message, setMessage] = useState('');
const [buttons, setButtons] = useState<AlertButton[]>([]);
const [options, setOptions] = useState<AlertOptions>({});

const isDark = Appearance.getColorScheme() === 'dark';
const colors = isDark ? BlueDarkTheme.colors : BlueDefaultTheme.colors;
Comment on lines +16 to +17
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.

instead of Appearance.getColorScheme - which just takes a snapshot, we should use useColorScheme.

Suggested change
const isDark = Appearance.getColorScheme() === 'dark';
const colors = isDark ? BlueDarkTheme.colors : BlueDefaultTheme.colors;
const colorScheme = useColorScheme();
const colors = colorScheme === 'dark' ? BlueDarkTheme.colors : BlueDefaultTheme.colors;


const dismiss = useCallback(() => setVisible(false), []);

useImperativeHandle(ref, () => ({
show: (t, m, b, o) => {
setTitle(t);
setMessage(m ?? '');
setButtons(b);
setOptions(o);
setVisible(true);
},
}));

const handlePress = useCallback(
(onPress?: () => void) => {
dismiss();
onPress?.();
},
[dismiss],
);

const getButtonTextStyle = (style?: string) => {
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.

Suggested change
const getButtonTextStyle = (style?: string) => {
const getButtonTextStyle = (style?: AlertButton['style']) => {

switch (style) {
case 'destructive':
return { color: colors.redText, fontWeight: '600' as const };
case 'cancel':
return { color: colors.foregroundColor, fontWeight: '600' as const };
default:
return { color: colors.primary };
}
};

return (
<Modal transparent visible={visible} animationType="fade" onRequestClose={options.cancelable ? dismiss : undefined}>
<View style={styles.overlay}>
<View style={[styles.container, { backgroundColor: colors.elevated }]}>
{title ? <Text style={[styles.title, { color: colors.foregroundColor }]}>{title}</Text> : null}
<Text style={[styles.message, { color: colors.foregroundColor }]}>{message}</Text>
<View style={[styles.buttonRow, { borderTopColor: colors.lightBorder }]}>
{buttons.map((button, index) => (
<TouchableOpacity
key={index}
accessibilityRole="button"
accessibilityLabel={button.text}
style={[

Check warning on line 62 in components/CustomAlert.tsx

View workflow job for this annotation

GitHub Actions / lint

Replace `⏎··················styles.button,⏎··················index·>·0·&&·{·borderLeftWidth:·StyleSheet.hairlineWidth,·borderLeftColor:·colors.lightBorder·},⏎················` with `styles.button,·index·>·0·&&·{·borderLeftWidth:·StyleSheet.hairlineWidth,·borderLeftColor:·colors.lightBorder·}`
styles.button,
index > 0 && { borderLeftWidth: StyleSheet.hairlineWidth, borderLeftColor: colors.lightBorder },
Comment thread
chaitika marked this conversation as resolved.
]}
onPress={() => handlePress(button.onPress ?? undefined)}
>
<Text style={[styles.buttonText, getButtonTextStyle(button.style)]}>{button.text}</Text>
</TouchableOpacity>
))}
</View>
</View>
</View>
</Modal>
);
});

const styles = StyleSheet.create({
overlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
},
container: {
width: '80%',
borderRadius: 14,
paddingTop: 20,
overflow: 'hidden',
},
title: {
fontSize: 17,
fontWeight: '600',
textAlign: 'center',
marginBottom: 4,
paddingHorizontal: 20,
},
message: {
fontSize: 14,
textAlign: 'center',
paddingHorizontal: 20,
paddingBottom: 20,
},
buttonRow: {
flexDirection: 'row',
borderTopWidth: StyleSheet.hairlineWidth,
},
button: {
flex: 1,
paddingVertical: 12,
alignItems: 'center',
justifyContent: 'center',
},
buttonText: {
fontSize: 16,
},
});

export default CustomAlert;
4 changes: 3 additions & 1 deletion components/themes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export const BlueDarkTheme: Theme = {
background: '#000000',
foregroundColor: '#ffffff',
buttonDisabledBackgroundColor: '#3A3A3C',
buttonBackgroundColor: '#FF9500',
buttonBackgroundColor: '#754CE8',
buttonTextColor: '#ffffff',
lightButton: 'rgba(255,255,255,.1)',
buttonAlternativeTextColor: '#ffffff',
Expand Down Expand Up @@ -129,6 +129,8 @@ export const BlueDarkTheme: Theme = {
receiveText: '#37C0A1',
navigationBarColor: '#3A3A3C',
androidRippleColor: '#444444',
primary: '#754CE8',
secondary: '#472EBF',
},
};

Expand Down
6 changes: 4 additions & 2 deletions loc/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -411,11 +411,12 @@
"details_address": "Address",
"details_advanced": "Advanced",
"details_are_you_sure": "Are you sure?",
"delete_wallet_warning": "You'll need your seed phrase to restore access.",
"details_connected_to": "Connected to",
"details_del_wb_err": "The provided balance amount does not match this wallet’s balance. Please try again.",
"details_del_wb_q": "This wallet has a balance. Before proceeding, please be aware that you will not be able to recover the funds without this wallet’s seed phrase. In order to avoid accidental removal, please enter your wallet’s balance of {balance} satoshis.",
"details_delete": "Delete",
"details_delete_wallet": "Delete Wallet",
"details_delete_wallet": "⚠️ Delete Wallet?",
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.

get rid of the emoji here. localization files carry text context

"details_derivation_path": "derivation path",
"details_display": "Display in Home Screen",
"details_export_backup": "Export/Backup",
Expand All @@ -427,7 +428,7 @@
"details_title": "Wallet",
"details_type": "Type",
"details_use_with_hardware_wallet": "Use with Hardware Wallet",
"details_yes_delete": "Yes, delete",
"details_yes_delete": "Delete",
"enter_bip38_password": "Enter password to decrypt",
"export_title": "Wallet Export",
"import_do_import": "Import",
Expand Down Expand Up @@ -465,6 +466,7 @@
"list_title": "Wallets",
"list_tryagain": "Try again",
"no_ln_wallet_error": "Before paying a Lightning invoice, you must first add a Lightning wallet.",
"no_wallet_to_delete": "No wallet available to delete",
"looks_like_bip38": "This looks like a password-protected private key (BIP38).",
"manage_title": "Manage Wallets",
"no_results_found": "No results found.",
Expand Down
2 changes: 1 addition & 1 deletion navigation/LazyLoadingIndicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ActivityIndicator, StyleSheet, View } from 'react-native';

export const LazyLoadingIndicator = () => (
<View style={styles.root}>
<ActivityIndicator size="large" />
<ActivityIndicator size="large" color="#754CE8" />
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.

we shouldn't hard-code colors

</View>
);

Expand Down
2 changes: 1 addition & 1 deletion screen/UnlockWith.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ const UnlockWith: React.FC = () => {

const renderUnlockOptions = () => {
if (state.isAuthenticating) {
return <ActivityIndicator />;
return <ActivityIndicator color="#754CE8" />;
} else {
switch (state.auth.type) {
case AuthType.Biometrics:
Expand Down
16 changes: 8 additions & 8 deletions screen/settings/DeleteWallet.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useCallback } from 'react';
import { Alert } from 'react-native';
import ListItem from '../../components/ListItem';
import { useStorage } from '../../hooks/context/useStorage';
import triggerHapticFeedback, { HapticFeedbackTypes } from '../../blue_modules/hapticFeedback';
Expand All @@ -8,6 +7,7 @@ import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
import { DetailViewStackParamList } from '../../navigation/DetailViewStackParamList';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { CommonActions } from '@react-navigation/native';
import presentAlert from '../../components/Alert';

type NavigationProps = NativeStackNavigationProp<DetailViewStackParamList, 'DeleteWallet'>;

Expand All @@ -18,14 +18,14 @@ const DeleteWallet: React.FC = () => {
const handleDeleteWallet = useCallback(async () => {
const wallet = wallets.length > 0 ? wallets[0] : null;
if (!wallet) {
Alert.alert(loc.wallets.list_empty_txs1, 'No wallet available to delete');
presentAlert({ title: loc.wallets.list_empty_txs1, message: loc.wallets.no_wallet_to_delete });
return;
}

Alert.alert(
loc.wallets.details_delete_wallet,
loc.wallets.details_are_you_sure,
[
presentAlert({
title: loc.wallets.details_delete_wallet,
message: loc.wallets.delete_wallet_warning,
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.

i think the message should be a combination of both, are you sure + you will need your seed phrase

buttons: [
{
text: loc._.cancel,
style: 'cancel',
Expand All @@ -47,8 +47,8 @@ const DeleteWallet: React.FC = () => {
},
},
],
{ cancelable: false },
);
options: { cancelable: false },
});
}, [wallets, handleWalletDeletion, dispatch]);

if (wallets.length === 0) {
Expand Down
1 change: 1 addition & 0 deletions screen/wallets/ImportWallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ const ImportWallet = () => {
const styles = StyleSheet.create({
root: {
paddingTop: 10,
flexGrow: 1,
},
center: {
flex: 1,
Expand Down
2 changes: 1 addition & 1 deletion screen/wallets/WalletDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ const WalletDetails: React.FC = () => {
triggerHapticFeedback(HapticFeedbackTypes.NotificationWarning);
presentAlert({
title: loc.wallets.details_delete_wallet,
message: loc.wallets.details_are_you_sure,
message: loc.wallets.delete_wallet_warning,
buttons: [
{
text: loc.wallets.details_yes_delete,
Expand Down
Loading