Skip to content
Merged
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
16 changes: 11 additions & 5 deletions app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { Image, LogBox, TouchableOpacity, Platform, View } from 'react-native';
import { supportsLiquidGlass } from '@/shared/lib/version';

import AppGate from '@/shared/blocks/AppGate';
import GlobalMigrationGate from '@/shared/blocks/GlobalMigrationGate';
import LegacyMigrationGate from '@/shared/blocks/LegacyMigrationGate';
import MigrationGate from '@/shared/blocks/MigrationGate';
import {
InitializationProvider,
Expand Down Expand Up @@ -396,11 +398,15 @@ export default function RootLayout() {
<TransitionControlRegistrar />
<TransitionGuardCleanup />
<NativeSplashLayoutGate>
<AccountScopedProviders
key={`account-${activeAccountIndex}`}
accountIndex={activeAccountIndex}>
<RootLayoutContent />
</AccountScopedProviders>
<LegacyMigrationGate>
<GlobalMigrationGate>
<AccountScopedProviders
key={`account-${activeAccountIndex}`}
accountIndex={activeAccountIndex}>
<RootLayoutContent />
</AccountScopedProviders>
</GlobalMigrationGate>
</LegacyMigrationGate>
</NativeSplashLayoutGate>
<PopupHost />
</OuterProviders>
Expand Down
32 changes: 28 additions & 4 deletions features/settings/screens/SettingsStorageScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { RefreshControl, ScrollView } from 'react-native';
import { RefreshControl, ScrollView, Share } from 'react-native';

import { Button, Card } from 'heroui-native';

import Container from '@/shared/ui/composed/Container';
import {
getFullAsyncStorageDump,
getStorageInventorySnapshot,
type ZustandInventory,
} from '@/shared/lib/debug/storageInventory';
Expand Down Expand Up @@ -160,6 +161,7 @@ export const SettingsStorageScreen = () => {

const [isLoading, setIsLoading] = useState(true);
const [isRefreshing, setIsRefreshing] = useState(false);
const [isSharing, setIsSharing] = useState(false);
const [error, setError] = useState<string | null>(null);
const [zustandGroups, setZustandGroups] = useState<ZustandInventory>(EMPTY_ZUSTAND_GROUPS);
const [secureStoreKeys, setSecureStoreKeys] = useState<string[]>([]);
Expand Down Expand Up @@ -204,6 +206,19 @@ export const SettingsStorageScreen = () => {
void loadSnapshot();
}, [loadSnapshot]);

const handleShareDump = useCallback(async () => {
setIsSharing(true);
try {
const dump = await getFullAsyncStorageDump();
const jsonString = JSON.stringify(dump, null, 2);
await Share.share({ message: jsonString, title: 'AsyncStorage Full Dump' });
} catch (shareError) {
setError(shareError instanceof Error ? shareError.message : 'Share failed');
} finally {
setIsSharing(false);
}
}, []);

const subtitle = useMemo(() => {
if (isLoading) {
return 'Loading storage inventory...';
Expand Down Expand Up @@ -265,9 +280,18 @@ export const SettingsStorageScreen = () => {
SecureStore cannot enumerate all keys. This probes deterministic keys from known
profile/account data and reports which currently exist.
</Text>
<Button variant="secondary" size="sm" onPress={() => loadSnapshot(true)}>
<Button.Label>Refresh</Button.Label>
</Button>
<View className="flex-row gap-2">
<Button variant="secondary" size="sm" onPress={() => loadSnapshot(true)}>
<Button.Label>Refresh</Button.Label>
</Button>
<Button
variant="secondary"
size="sm"
isDisabled={isSharing}
onPress={handleShareDump}>
<Button.Label>{isSharing ? 'Exporting...' : 'Share Full Dump'}</Button.Label>
</Button>
</View>
{error ? (
<Text size={12} className="text-danger">
Failed to refresh inventory: {error}
Expand Down
23 changes: 12 additions & 11 deletions redux/cashu/reducer.deprecated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ import type { AnyAction, Reducer } from 'redux';
import { typedUpdate } from '@/shared/lib/typedUpdate';
import { cashuState } from '@/redux/store/migrationTest.deprecated';

const p0 = Array.isArray(cashuState.profiles) ? cashuState.profiles[0] : cashuState.profiles;
const initialState: CashuState = {
profiles: [
{
selectedMint: cashuState.selectedMint,
mints: [],
proofs: cashuState.profiles.proofs,
counters: cashuState.profiles.counters,
keysets: {},
transactions: [],
selectedMint: p0?.selectedMint,
mints: p0?.mints || [],
proofs: p0?.proofs || {},
counters: p0?.counters || {},
keysets: p0?.keysets || {},
transactions: p0?.transactions || [],
},
],
audits: {},
info: {},
keys: {},
keysets: {},
allocation: {},
audits: cashuState.audits || {},
info: cashuState.info || {},
keys: cashuState.keys || {},
keysets: cashuState.keysets || {},
allocation: cashuState.allocation || {},
};

export const cashuReducer: Reducer<CashuState, AnyAction> = (state = initialState, action) => {
Expand Down
34 changes: 17 additions & 17 deletions redux/nostr/reducer.deprecated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,45 +37,45 @@ type Profile = {

type NostrState = {
currentProfile: { id: number };
search?: any[];
profiles: Profile[];
messages: {
loaded_messages: any[];
[key: string]: Message[];
};
follows: Record<string, any>;
contacts?: any[];
};

const p = nostrState.profiles[0];
const initialState: NostrState = {
currentProfile: {
id: nostrState.currentProfile.id,
},
...(nostrState.search ? { search: nostrState.search as any[] } : {}),
profiles: [
{
id: nostrState.profiles[0].id,
mnemonic: nostrState.profiles[0].mnemonic || '',
pubkey: '',
profile: {
id: p.id,
mnemonic: p.mnemonic || '',
pubkey: p.pubkey || '',
profile: p.profile || {
created_at: 0,
profileEvent: '',
name: '',
picture: '',
image: '',
},
npub: '',
nsec: '',
mints: [],
picture: '',
root: {
xpub: '',
xpriv: '',
},
nut13: '',
npub: p.npub || '',
nsec: p.nsec || '',
mints: p.mints || [],
picture: p.picture || '',
root: p.root || { xpub: '', xpriv: '' },
nut13: p.nut13 || '',
},
],
messages: {
loaded_messages: [],
},
follows: {},
messages: nostrState.messages || { loaded_messages: [] },
follows: nostrState.follows || {},
...(nostrState.contacts ? { contacts: nostrState.contacts as any[] } : {}),
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down
100 changes: 60 additions & 40 deletions redux/store/migrationTest.deprecated.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,70 @@
import { Proof } from '@cashu/cashu-ts';

const id = 0;
const mnemonic = undefined; // 'crumble stamp weapon meadow tilt logic winter mean tooth bracket wool fire';

export const nostrState = {
currentProfile: {
id: 0,
},
search: [
{
pubkey: '1e53e900c3bbc5ead295215efe27b2c8d5fbd15fb3dd810da3063674cb7213b2',
profile: {
created_at: 1724764804,
profileEvent:
'{"created_at":1738834915,"content":"{\\"displayName\\":\\"Sovran Bitcoin\\",\\"display_name\\":\\"Sovran Bitcoin\\",\\"name\\":\\"Sovran\\",\\"website\\":\\"https://sovranbitcoin.com\\",\\"about\\":\\"Working on a Bitcoin wallet that I like to use.\\",\\"lud16\\":\\"maskedroom40@walletofsatoshi.com\\",\\"picture\\":\\"https://m.primal.net/IEAX.png\\",\\"pubkey\\":\\"1e53e900c3bbc5ead295215efe27b2c8d5fbd15fb3dd810da3063674cb7213b2\\",\\"npub\\":\\"npub1ref7jqxrh0z74554y900ufajer2lh52lk0wczrdrqcm8fjmjzweqll64x3\\",\\"created_at\\":1724764804,\\"banner\\":\\"https://m.primal.net/Kgxi.png\\"}","tags":[],"kind":0,"pubkey":"1e53e900c3bbc5ead295215efe27b2c8d5fbd15fb3dd810da3063674cb7213b2","id":"97b889880504d1b0b70277076e51156b3c8d88d27acfa86882667be654aa228d","sig":"5f809e1604d84c58341664d362eb15f3d32e7faf73c9b675228a1ad4250bb80fd4ff3db7e314a7748412686abe2a7ba0e1fc0384ee72217ad82b0fcea20c4db8"}',
displayName: 'Sovran Bitcoin',
name: 'Sovran',
website: 'https://sovranbitcoin.com',
about: 'Working on a Bitcoin wallet that I like to use.',
lud16: 'maskedroom40@walletofsatoshi.com',
image: 'https://m.primal.net/IEAX.png',
pubkey: '1e53e900c3bbc5ead295215efe27b2c8d5fbd15fb3dd810da3063674cb7213b2',
npub: 'npub1ref7jqxrh0z74554y900ufajer2lh52lk0wczrdrqcm8fjmjzweqll64x3',
banner: 'https://m.primal.net/Kgxi.png',
},
},
],
profiles: [
{
id,
mnemonic,
id: 0,
mnemonic: '',
pubkey: '',
profile: {
created_at: 0,
profileEvent: '',
name: '',
picture: '',
image: '',
},
npub: '',
nsec: '',
mints: [],
picture: '',
root: {
xpub: '',
xpriv: '',
},
nut13: '',
},
],
currentProfile: {
id,
mnemonic,
messages: {
loaded_messages: [],
},
follows: {},
contacts: [],
};

const mintAToken = undefined; // 'cashuBo2FteBtodHRwczovL3Rlc3RudXQuY2FzaHUuc3BhY2VhdWN1c2RhdIGiYWlIAMB0uWx-Kw5hcIakYWEYQGFzeEBkMmJhOGNhMzUzNDQxMDIzMDBiMmUzNTM4OGI1NjMwOTMyNDQ5YjkzNGFhYjEzMDFiMjI0YWFlYzY3YjYzNGJlYWNYIQPYbav6VZekE2kd5gFEi-6zYdoXHb6Uoep1R-z6-yVuIWFko2FlWCAGFY0Yrmhv3_MuQbIM3JGRFQAFbWQLdZ5zpNAMd3VZA2FzWCAD-c30XB1HaoNpZViBjF5mZoHLQ-I5g41MP36nsMCDAmFyWCBUYffqkCs0XhEfBiGfPy8tWtKghEChQeKbVgSqy3rCdKRhYRBhc3hAMDE0NmNmZWU4ODI2MzQ0YzhlMDYxZWExM2EwMjMyZTU0ZDVmM2NkNzVhZDIzZGU0MWEzOGZiNDM2NTE5Y2I4ZGFjWCECHR2ETAEFvRGofDj2c2VZDU3AAI8QhPj2UPOiZax9SwthZKNhZVggtoDpHu-PcjDNglwa-oRYoHbaUtT1lLE7ErKrLbpFKnphc1ggeA-m-DEm0na_L-y2u9zdMMVJ8w_JXbphN48_xZ4GhmhhclggWpfGRnSOMUl7YenB1pkk6v3LiKXelfr7hWZXiMJF5E2kYWEQYXN4QDZhMGQzZjM3MWUyMjE5ZjVhN2JiYzBkZTBmZTkzZWFmNWY1YjA4NjljNmQ1MTNhOGVkNDRlZDZmMmE5MzNmZTNhY1ghAr_OTP7lT6X0vVqezA2JdptYjDtuo-uI-e93Ce38Q0zMYWSjYWVYIOLf9d1J-NF906IE_r8igzRfwtgZEPdUa92oz1PjL93gYXNYINDfO3VylWvGAkePiduG6A1ljNzcXtnhm-9131ehlE7ZYXJYIAx7bGXSg7_Kka6r-pHmmY-VyW6VoI8t19NwjNJhvNerpGFhAmFzeEBiY2UxNzExNmIxZWZkMmY3MGU2YjQ1YTAwZWRjOWM0ZTVhY2E2YjgwOTUxOThlZmVmYjgwOWQ3Mjk2ZTA0OTllYWNYIQIjReL5rwNJSHdQQSEnRie2crZJp4vyYivpUguJv2laoGFko2FlWCDQZZvYdrTvziJ4LQivxjSNizTIEe_lA5nTJpbv5AxROWFzWCAJ-lcZBuG24w9qmD2Cl65T45XdN8CLfR5eIUqCNFEvBWFyWCA0aDLmFAcF9kIg4aU3j4d3cfmvWS-VS_0XS2ry7bReuaRhYQFhc3hAYzhlNDk2OGM4OWMzOTg0MjRiYWZhOTMxMGUzOGIzYzY0N2MzMDIxNDE3YzNkNDc0MTQ1NWI2NjI0NGQ2ZDJhNWFjWCEDc9K21A6OOPZ-tZHQxzBdkyAJCA1ndhxI9ynIbWILgQdhZKNhZVggZs5lOwBNiIJPk4CqQN41hstH1AOIReMd76wSMIAegb5hc1ggxgsmJ92E1bjs7L5_UfUMF_4JNy_ofBbqUh95JTrw511hclggJrUmFPrg6VKjfN4vwCNOq7IQ_Niey4svGWXpenBiQ_6kYWEBYXN4QDY4YTFiMGMwYmI0ZmJlODZmMzA2OTYyZDYwMjZkNjU4MTJmMGU1NzdiYTZmY2VjYmIyMWZmOTMwMzA0MTk3YzNhY1ghAinsDc1YOTj_3F3Hiu_9YbIRzx3kamgXEYFP38-xGQpCYWSjYWVYID_yNplssQD7JGW7lfv1UJyEDRBSdNJDmt-uZpM8c7ViYXNYICK46IsyGF_W8lv9fSpAwcCD-QMaOZUJNzsSI6HsnnLvYXJYIEG0OsMPM-3M-Wn6kR1tfOl6iTGw78cLXM8lKYd_J41h';
type DecodedToken = { mint: string; proofs: Proof[] };
const decodedMintAToken: DecodedToken | undefined = undefined; //getDecodedToken(mintAToken);

// Extract values to avoid TypeScript narrowing issues
// Use explicit type guard to help TypeScript
let mintUrl: string | undefined = undefined;
let proofs: Proof[] | undefined = undefined;
if (decodedMintAToken !== undefined && decodedMintAToken !== null) {
const token: DecodedToken = decodedMintAToken;
mintUrl = token.mint;
proofs = token.proofs;
}

export const cashuState = {
selectedMint: mintUrl,
profiles: {
mints: mintUrl ? [mintUrl] : [],
counters:
mintUrl && proofs
? {
[mintUrl]: Object.fromEntries(proofs.map((proof: Proof) => [proof.id, 100])),
}
: {},
proofs:
mintUrl && proofs
? {
[mintUrl]: proofs,
}
: {},
},
profiles: [
{
selectedMint: undefined,
mints: [],
proofs: {},
keysets: {},
transactions: [],
counters: {},
},
],
keysets: {},
keys: {},
info: {},
audits: {},
allocation: {},
};
Loading
Loading