diff --git a/src/assets/icons/wallet.ts b/src/assets/icons/wallet.ts
index 8dbf94d8e..dc6b13028 100644
--- a/src/assets/icons/wallet.ts
+++ b/src/assets/icons/wallet.ts
@@ -182,9 +182,6 @@ export const usersIcon = (color = 'white'): string =>
export const userIcon = (color = 'white'): string =>
``;
-export const userRectangleIcon = (color = 'white'): string =>
- ``;
-
export const speedFastIcon = (color = 'white'): string =>
``;
diff --git a/src/screens/Settings/BackupSettings/index.tsx b/src/screens/Settings/BackupSettings/index.tsx
index 3d2259311..6a9e716d5 100644
--- a/src/screens/Settings/BackupSettings/index.tsx
+++ b/src/screens/Settings/BackupSettings/index.tsx
@@ -1,46 +1,47 @@
import React, { ReactElement, ReactNode, memo, useMemo } from 'react';
-import { StyleSheet, View } from 'react-native';
import { useTranslation } from 'react-i18next';
+import { StyleSheet, View } from 'react-native';
import { EItemType, IListData } from '../../../components/List';
-import SettingsView from '../SettingsView';
import { useAppDispatch, useAppSelector } from '../../../hooks/redux';
-import { showBottomSheet } from '../../../store/utils/ui';
import { SettingsScreenProps } from '../../../navigation/types';
-import { Caption13M, Caption13Up, Text01M } from '../../../styles/text';
+import { backupSelector } from '../../../store/reselect/backup';
+import { lightningBackupSelector } from '../../../store/reselect/lightning';
+import { forceBackup } from '../../../store/slices/backup';
+import { TBackupItem } from '../../../store/types/backup';
+import { EBackupCategories } from '../../../store/utils/backup';
+import { showBottomSheet } from '../../../store/utils/ui';
import {
ScrollView,
- TouchableOpacity,
View as ThemedView,
+ TouchableOpacity,
} from '../../../styles/components';
-import { backupSelector } from '../../../store/reselect/backup';
import {
ArrowClockwise,
- // LightningHollow,
+ LightningHollow,
NoteIcon,
RectanglesTwo,
SettingsIcon,
TagIcon,
- // TransferIcon,
UsersIcon,
- // UserRectangleIcon,
} from '../../../styles/icons';
-import { i18nTime } from '../../../utils/i18n';
-import { EBackupCategories } from '../../../store/utils/backup';
-import { forceBackup } from '../../../store/slices/backup';
+import { Caption13M, Caption13Up, Text01M } from '../../../styles/text';
import { IThemeColors } from '../../../styles/themes';
-import { TBackupItem } from '../../../store/types/backup';
+import { i18nTime } from '../../../utils/i18n';
+import SettingsView from '../SettingsView';
const Status = ({
Icon,
title,
status,
category,
+ disableRetry,
}: {
Icon: React.FunctionComponent;
title: ReactNode;
status: TBackupItem;
- category: EBackupCategories;
+ category?: EBackupCategories;
+ disableRetry?: boolean;
}): ReactElement => {
const { t } = useTranslation('settings');
const { t: tTime } = useTranslation('intl', { i18n: i18nTime });
@@ -93,7 +94,9 @@ const Status = ({
}
const retry = (): void => {
- // setHideRetry(true);
+ if (!category) {
+ return;
+ }
dispatch(forceBackup({ category }));
};
@@ -108,7 +111,7 @@ const Status = ({
{title}
{subtitle}
- {showRetry && (
+ {!disableRetry && showRetry && (
@@ -117,21 +120,36 @@ const Status = ({
);
};
+type TBackupCategory = {
+ Icon: React.FunctionComponent;
+ title: string;
+ category?: EBackupCategories;
+ status: TBackupItem;
+ disableRetry?: boolean;
+};
+
const BackupSettings = ({
navigation,
}: SettingsScreenProps<'BackupSettings'>): ReactElement => {
const { t } = useTranslation('settings');
const pin = useAppSelector((state) => state.settings.pin);
const backup = useAppSelector(backupSelector);
+ const lightningBackup = useAppSelector(lightningBackupSelector);
- const categories = [
- // {
- // Icon: LightningHollow,
- // title: t('backup.category_connections'),
- // isSyncedKey: 'remoteLdkBackupSynced',
- // lastSync: backup.remoteLdkBackupLastSync,
- // syncRequired: backup.remoteLdkBackupLastSyncRequired,
- // },
+ // find lightning latest backup item to show
+ const lightning = useMemo(() => {
+ const channels = Object.entries(lightningBackup).filter(([key]) =>
+ key.startsWith('channel_'),
+ );
+ if (channels.length === 0) {
+ return;
+ }
+ return channels.reduce((acc, [, value]) => {
+ return value.lastQueued > acc.lastQueued ? value : acc;
+ }, channels[0][1]);
+ }, [lightningBackup]);
+
+ const categories: Array = [
{
Icon: NoteIcon,
title: t('backup.category_connection_receipts'),
@@ -177,6 +195,19 @@ const BackupSettings = ({
},
];
+ if (lightning) {
+ categories.unshift({
+ Icon: LightningHollow,
+ title: t('backup.category_connections'),
+ status: {
+ running: false,
+ synced: lightning.lastPersisted ?? 0,
+ required: lightning.lastQueued,
+ },
+ disableRetry: true,
+ });
+ }
+
const settingsListData: IListData[] = useMemo(
() => [
{
diff --git a/src/store/migrations/index.ts b/src/store/migrations/index.ts
index d51b9fc64..6b6cc4ec2 100644
--- a/src/store/migrations/index.ts
+++ b/src/store/migrations/index.ts
@@ -364,12 +364,25 @@ const migrations = {
};
},
34: (state): PersistedState => {
+ const newNodes = { ...state.lightning.nodes };
+ // Loop through all nodes
+ for (const walletName in newNodes) {
+ newNodes[walletName] = {
+ ...newNodes[walletName],
+ backup: getNetworkContent({}),
+ };
+ }
+
return {
...state,
backup: {
...initialBackupState,
...state.backup,
},
+ lightning: {
+ ...state.lightning,
+ nodes: newNodes,
+ },
};
},
};
diff --git a/src/store/reselect/lightning.ts b/src/store/reselect/lightning.ts
index 422eaf2e7..58eaf77a9 100644
--- a/src/store/reselect/lightning.ts
+++ b/src/store/reselect/lightning.ts
@@ -219,3 +219,11 @@ export const lightningBalanceSelector = createSelector(
};
},
);
+
+export const lightningBackupSelector = createSelector(
+ [lightningState, selectedWalletSelector, selectedNetworkSelector],
+ (lightning, selectedWallet, selectedNetwork) => {
+ const node = lightning.nodes[selectedWallet];
+ return node?.backup[selectedNetwork] ?? {};
+ },
+);
diff --git a/src/store/shapes/lightning.ts b/src/store/shapes/lightning.ts
index bd23617a7..ab9239ad5 100644
--- a/src/store/shapes/lightning.ts
+++ b/src/store/shapes/lightning.ts
@@ -8,6 +8,7 @@ export const defaultLightningShape: TNode = {
openChannelIds: getNetworkContent([]),
peers: getNetworkContent([]),
claimableBalances: getNetworkContent([]),
+ backup: getNetworkContent({}),
};
export const initialLightningState: TLightningState = {
diff --git a/src/store/slices/lightning.ts b/src/store/slices/lightning.ts
index 2c234cfb0..c951a0f40 100644
--- a/src/store/slices/lightning.ts
+++ b/src/store/slices/lightning.ts
@@ -1,5 +1,8 @@
import { PayloadAction, createSlice } from '@reduxjs/toolkit';
-import { TClaimableBalance } from '@synonymdev/react-native-ldk';
+import {
+ TBackupStateUpdate,
+ TClaimableBalance,
+} from '@synonymdev/react-native-ldk';
import { initialLightningState } from '../shapes/lightning';
import { EAvailableNetwork } from '../../utils/networks';
@@ -87,6 +90,17 @@ export const lightningSlice = createSlice({
state.nodes[selectedWallet].claimableBalances[selectedNetwork] =
claimableBalances;
},
+ updateBackupState: (
+ state,
+ action: PayloadAction<{
+ backup: TBackupStateUpdate;
+ selectedWallet: TWalletName;
+ selectedNetwork: EAvailableNetwork;
+ }>,
+ ) => {
+ const { backup, selectedWallet, selectedNetwork } = action.payload;
+ state.nodes[selectedWallet].backup[selectedNetwork] = backup;
+ },
updateLdkAccountVersion: (
state,
action: PayloadAction,
@@ -106,6 +120,7 @@ export const {
saveLightningPeer,
removeLightningPeer,
updateClaimableBalances,
+ updateBackupState,
updateLdkAccountVersion,
resetLightningState,
} = actions;
diff --git a/src/store/types/lightning.ts b/src/store/types/lightning.ts
index 989211611..e27a0d0f2 100644
--- a/src/store/types/lightning.ts
+++ b/src/store/types/lightning.ts
@@ -1,4 +1,5 @@
import {
+ TBackupStateUpdate,
TChannel,
TClaimableBalance,
TCreatePaymentReq,
@@ -27,6 +28,7 @@ export type TNode = {
info: IWalletItem<{}>;
peers: IWalletItem;
claimableBalances: IWalletItem;
+ backup: IWalletItem;
};
export type TNodes = {
diff --git a/src/styles/icons.ts b/src/styles/icons.ts
index 4d525fc7d..df38cf5ec 100644
--- a/src/styles/icons.ts
+++ b/src/styles/icons.ts
@@ -27,7 +27,6 @@ import {
clipboardTextIcon,
usersIcon,
userIcon,
- userRectangleIcon,
speedFastIcon,
speedNormalIcon,
speedSlowIcon,
@@ -282,16 +281,6 @@ export const UserIcon = styled(SvgXml).attrs((props) => ({
color: props.color ? props.theme.colors[props.color] : 'white',
}));
-export const UserRectangleIcon = styled(SvgXml).attrs((props) => ({
- xml: userRectangleIcon(
- props.color ? props.theme.colors[props.color] : 'white',
- ),
- height: props.height ?? '32px',
- width: props.width ?? '32px',
-}))((props) => ({
- color: props.color ? props.theme.colors[props.color] : 'white',
-}));
-
export const SpeedFastIcon = styled(SvgXml).attrs((props) => ({
xml: speedFastIcon(props.color ? props.theme.colors[props.color] : 'white'),
height: props.height ?? '32px',
diff --git a/src/utils/lightning/index.ts b/src/utils/lightning/index.ts
index 0aba4387c..d9fd7008f 100644
--- a/src/utils/lightning/index.ts
+++ b/src/utils/lightning/index.ts
@@ -23,6 +23,7 @@ import lm, {
TPaymentReq,
TTransactionData,
TTransactionPosition,
+ TBackupStateUpdate,
} from '@synonymdev/react-native-ldk';
import {
@@ -50,6 +51,7 @@ import {
} from '../../store/helpers';
import { defaultHeader } from '../../store/shapes/wallet';
import {
+ updateBackupState,
updateLdkAccountVersion,
updateLightningNodeId,
} from '../../store/slices/lightning';
@@ -111,6 +113,7 @@ export const FALLBACK_BLOCKTANK_PEERS: IWalletItem = {
let paymentSubscription: EmitterSubscription | undefined;
let onChannelSubscription: EmitterSubscription | undefined;
let onSpendableOutputsSubscription: EmitterSubscription | undefined;
+let onBackupStateUpdate: EmitterSubscription | undefined;
/**
* Wipes LDK data from storage
@@ -467,12 +470,34 @@ export const subscribeToLightningPayments = ({
() => {},
);
}
+ if (!onBackupStateUpdate) {
+ onBackupStateUpdate = ldk.onEvent(
+ EEventTypes.backup_state_update,
+ (res: TBackupStateUpdate) => {
+ if (!selectedWallet) {
+ selectedWallet = getSelectedWallet();
+ }
+ if (!selectedNetwork) {
+ selectedNetwork = getSelectedNetwork();
+ }
+
+ dispatch(
+ updateBackupState({
+ backup: res,
+ selectedWallet,
+ selectedNetwork,
+ }),
+ );
+ },
+ );
+ }
};
export const unsubscribeFromLightningSubscriptions = (): void => {
paymentSubscription?.remove();
onChannelSubscription?.remove();
onSpendableOutputsSubscription?.remove();
+ onBackupStateUpdate?.remove();
};
let isRefreshing = false;