Skip to content

Commit

Permalink
Nostr (#238)
Browse files Browse the repository at this point in the history
* hide wallet amounts by pressing on logo #226 (#227)

* add 0.0.4 sig

* cleanup

* update Nostr Support

* update deps

---------

Co-authored-by: First-Terraner <[email protected]>
Co-authored-by: KKA11010 <[email protected]>
  • Loading branch information
3 people authored Sep 25, 2023
1 parent 519726d commit 7cd2462
Show file tree
Hide file tree
Showing 13 changed files with 502 additions and 447 deletions.
768 changes: 384 additions & 384 deletions package-lock.json

Large diffs are not rendered by default.

44 changes: 19 additions & 25 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@
"author": "Agron Kadriaj <[email protected]> (https://agron.dev)",
"scripts": {
"s:debug:full": "npx -y cross-env@latest DEBUG=full expo start -c",
"s:c:dev": "expo start -c --dev-client",
"s:c": "expo start -c --go",
"start": "expo start --go",
"start:d": "expo start",
"lint:eslint": "npx eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.json --fix",
"lint:eslint": "npx eslint ./src --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts,.json --fix",
"lint": "npm run lint:eslint && npx tsc && npm run fmtJson",
"ts:check": "npx tsc",
"dep:update": "npx -y npm-check-updates --pre -u -u && npm i && npm audit fix || true && npx expo install --fix && npm run lint",
Expand All @@ -31,10 +29,6 @@
"web": "expo start --web",
"test": "npx jest -c ./config/jest.config.ts --passWithNoTests ",
"test:coverage": "npm run test -- --collectCoverage",
"test:ts": "npm run test --testPathIgnorePatterns=tsx$",
"test:ts:coverage": "npm run test:ts -- --collectCoverageFrom=src/**/*.ts",
"test:tsx": "npm run test --testPathIgnorePatterns=ts$",
"test:tsx:coverage": "npm run test:tsx -- --collectCoverageFrom=components/**/*.tsx",
"test:dev": "npm run test -- --detectOpenHandles",
"cpd:ts": "npx -y jscpd -c config/cpd.config.ts.json src config",
"cpd:tsx": "npx -y jscpd -c config/cpd.config.tsx.json src",
Expand All @@ -49,12 +43,12 @@
"@react-native-async-storage/async-storage": "1.18.2",
"@react-native-community/netinfo": "9.3.10",
"@react-navigation/core": "^6.4.9",
"@react-navigation/native": "^6.1.7",
"@react-navigation/native-stack": "^6.9.13",
"@react-navigation/native": "^6.1.8",
"@react-navigation/native-stack": "^6.9.14",
"@sentry/react-native": "5.5.0",
"@shopify/flash-list": "1.4.3",
"crypto-js": "4.1.1",
"expo": "^49.0.9",
"expo": "^49.0.11",
"expo-application": "~5.3.0",
"expo-asset": "~8.10.1",
"expo-barcode-scanner": "~12.5.3",
Expand All @@ -64,7 +58,7 @@
"expo-crypto": "~12.4.1",
"expo-device": "~5.4.0",
"expo-file-system": "~15.4.4",
"expo-insights": "^0.2.0",
"expo-insights": "~0.2.0",
"expo-localization": "~14.3.0",
"expo-secure-store": "~12.3.1",
"expo-splash-screen": "~0.20.5",
Expand Down Expand Up @@ -92,25 +86,25 @@
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@getify/eslint-plugin-proper-arrows": "^11.0.3",
"@testing-library/react-native": "^12.3.0",
"@types/babel__core": "^7.20.1",
"@types/babel__core": "^7.20.2",
"@types/crypto-js": "^4.1.2",
"@types/eslint": "^8.44.2",
"@types/jest": "^29.5.4",
"@types/node": "^20.6.0",
"@types/react": "~18.2.21",
"@types/eslint": "^8.44.3",
"@types/jest": "^29.5.5",
"@types/node": "^20.6.5",
"@types/react": "~18.2.22",
"@types/react-native-onboarding-swiper": "^1.1.4",
"@types/sqlite3": "^3.1.8",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"@types/sqlite3": "^3.1.9",
"@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/parser": "^6.7.2",
"dotenv": "^16.3.1",
"eslint": "^8.49.0",
"eslint-plugin-deprecate": "^0.8.2",
"eslint": "^8.50.0",
"eslint-plugin-deprecate": "^0.8.3",
"eslint-plugin-es5": "^1.5.0",
"eslint-plugin-eslint-plugin": "^5.1.1",
"eslint-plugin-html": "^7.1.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jest": "^27.2.3",
"eslint-plugin-jsdoc": "^46.6.0",
"eslint-plugin-jest": "^27.4.0",
"eslint-plugin-jsdoc": "^46.8.2",
"eslint-plugin-json": "^3.1.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1",
Expand All @@ -119,9 +113,9 @@
"eslint-plugin-simple-import-sort": "^10.0.0",
"eslint-plugin-tsdoc": "^0.2.17",
"expo-dev-client": "~2.4.10",
"jest": "^29.6.4",
"jest": "^29.7.0",
"jest-expo": "^49.0.0",
"metro-config": "^0.79.0",
"metro-config": "^0.79.1",
"prettier": "^3.0.3",
"reactotron-react-native": "^5.0.3",
"ts-jest": "^29.1.1",
Expand Down
8 changes: 6 additions & 2 deletions src/components/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function Balance({ balance, nav }: IBalanceProps) {
const { pref, color, highlight } = useThemeContext()
// State to indicate token claim from clipboard after app comes to the foreground, to re-render total balance
const { claimed } = useFocusClaimContext()
const { hidden } = usePrivacyContext()
const { hidden, handleLogoPress } = usePrivacyContext()
const [formatSats, setFormatSats] = useState(pref?.formatBalance)
const [history, setHistory] = useState<IHistoryEntry[]>([])

Expand Down Expand Up @@ -75,7 +75,11 @@ export default function Balance({ balance, nav }: IBalanceProps) {
styles.board,
{ borderColor: color.BORDER, backgroundColor: hi[highlight] }
]}>
<Logo size={hidden.balance ? 100 : 40} style={{ marginTop: hidden.balance ? 40 : 0, marginBottom: hidden.balance ? 40 : 10 }} />
<TouchableOpacity
onPress={() => void handleLogoPress()}
>
<Logo size={hidden.balance ? 100 : 40} style={{ marginTop: hidden.balance ? 40 : 0, marginBottom: hidden.balance ? 40 : 10 }} />
</TouchableOpacity>
{/* balance */}
{!hidden.balance &&
<TouchableOpacity
Expand Down
49 changes: 47 additions & 2 deletions src/context/Privacy.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* eslint-disable no-return-await */
/* eslint-disable @typescript-eslint/await-thenable */
import { l } from '@log'
import { store } from '@store'
import { STORE_KEYS } from '@store/consts'
Expand All @@ -8,6 +10,42 @@ const usePrivacy = () => {
balance: false,
txs: false
})

const handleHiddenBalance = async () => {
setHidden({ balance: !hidden.balance, txs: hidden.txs })
if (hidden.balance) {
await store.delete(STORE_KEYS.hiddenBal)
return
}
await store.set(STORE_KEYS.hiddenBal, '1')
}

const handleHiddenTxs = async () => {
setHidden({ balance: hidden.balance, txs: !hidden.txs })
if (hidden.txs) {
await store.delete(STORE_KEYS.hiddenTxs)
return
}
await store.set(STORE_KEYS.hiddenTxs, '1')
}

const handleLogoPress = async () => {
// both hidden, show both
if (hidden.balance && hidden.txs) {
setHidden({ balance: false, txs: false })
await Promise.all([
store.delete(STORE_KEYS.hiddenTxs),
store.delete(STORE_KEYS.hiddenBal)
])
return
}
setHidden({ balance: true, txs: true })
await Promise.all([
store.set(STORE_KEYS.hiddenTxs, '1'),
store.set(STORE_KEYS.hiddenBal, '1')
])
}

useEffect(() => {
void (async () => {
// init privacy preferences
Expand All @@ -21,15 +59,22 @@ const usePrivacy = () => {
})
})()
}, [])

return {
hidden,
setHidden
setHidden,
handleHiddenBalance,
handleHiddenTxs,
handleLogoPress
}
}
type usePrivacyType = ReturnType<typeof usePrivacy>
const PrivacyContext = createContext<usePrivacyType>({
hidden: { balance: false, txs: false },
setHidden: () => l('')
setHidden: () => l(''),
handleHiddenBalance: async () => await l(''),
handleHiddenTxs: async () => await l(''),
handleLogoPress: async () => await l('')
})

export const usePrivacyContext = () => useContext(PrivacyContext)
Expand Down
25 changes: 23 additions & 2 deletions src/nostr/consts.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

/**
* Default bootstrap relays
*/
Expand Down Expand Up @@ -68,5 +69,25 @@ export const enutsPubkey = 'npub1dx5q2el8nd4eh3eg9t2e25fd7zuqg7zxz6ldkc3uzgh66ss
// export const defaultConnectTimeout = 2000


export const imgProxy = (url: string, width = 40) =>
`https://cf-worker-images.enuts.workers.dev/?_=${encodeURIComponent(url)}&s=${width ?? 40}`
const PREFIX = 'https://cf-worker-images.enuts.workers.dev'
export function imgProxy(
hex: string,
url: string,
width: number,
kind: 'picture',
size: 64 | 192): string
export function imgProxy(
hex: string,
url: string,
width: number,
kind: 'banner',
size: 600 | 1200): string
export function imgProxy(
hex: string,
url: string,
width = 40,
kind: 'picture' | 'banner' = 'picture',
size: 64 | 192 | 600 | 1200 = 64
): string {
return `${PREFIX}/hex/${hex}/${kind}/${size}?_=${encodeURIComponent(url)}&s=${width ?? 40}`
}
18 changes: 13 additions & 5 deletions src/screens/Addressbook/ProfilePic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@ import { Image } from 'expo-image'
import { useState } from 'react'
import { StyleSheet, View } from 'react-native'

export type TNostrImg = INostrImgBanner & INostrImgPicture & { url: string }
interface INostrImgBanner {
hex?: string
kind?: 'banner'
width?: 600 | 1200
}
interface INostrImgPicture {
hex?: string
kind?: 'picture'
width?: 64 | 192
}
interface IProfilePicProps {
uri?: string
size?: number
Expand All @@ -24,11 +35,7 @@ export default function ProfilePic({ uri, size, isUser, withPlusIcon, overlayCol
height: size || defaultSize,
borderRadius: size ? size / 2 : defaultSize / 2
}
// useEffect(() => {
// if (!isStr(uri) || !uri?.length) { return }
// void Image.prefetch(`${imgProxy(uri, circleStyle?.width ?? 40)}`)
// .catch(e => l('img preload', uri, e))
// }, [circleStyle?.width, uri])

return (
<>
{isStr(uri) && uri?.length && !isErr ?
Expand All @@ -38,6 +45,7 @@ export default function ProfilePic({ uri, size, isUser, withPlusIcon, overlayCol
// l({ uri, err })
setIsErr(true)
})}
// TODO FIXME
// source={`${imgProxy(uri, circleStyle?.width ?? 40)}`}
cachePolicy='memory-disk'
transition={200}
Expand Down
2 changes: 1 addition & 1 deletion src/screens/Addressbook/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function AddressbookPage({ navigation, route }: TAddressBookPageP
const [newNpubModal, setNewNpubModal] = useState(false)
const ref = useRef<NostrData>()
const isSending = route.params?.isMelt || route.params?.isSendEcash

const initNostr = useCallback((hex: string) => {
if (!hex) { return l('no hex') }
if (!ref?.current?.hex || hex !== ref.current.hex) {
Expand Down
22 changes: 1 addition & 21 deletions src/screens/Settings/Privacy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,14 @@ import BottomNav from '@nav/BottomNav'
import { usePrivacyContext } from '@src/context/Privacy'
import { useThemeContext } from '@src/context/Theme'
import { NS } from '@src/i18n'
import { store } from '@store'
import { STORE_KEYS } from '@store/consts'
import { globals, highlight as hi } from '@styles'
import { useTranslation } from 'react-i18next'
import { StyleSheet, Switch, Text, View } from 'react-native'

export default function PrivacySettings({ navigation, route }: TPrivacySettingsPageProps) {
const { t } = useTranslation([NS.topNav])
const { color, highlight } = useThemeContext()
const { hidden, setHidden } = usePrivacyContext()

const handleHiddenBalance = async () => {
setHidden({ balance: !hidden.balance, txs: hidden.txs })
if (hidden.balance) {
await store.delete(STORE_KEYS.hiddenBal)
return
}
await store.set(STORE_KEYS.hiddenBal, '1')
}

const handleHiddenTxs = async () => {
setHidden({ balance: hidden.balance, txs: !hidden.txs })
if (hidden.txs) {
await store.delete(STORE_KEYS.hiddenTxs)
return
}
await store.set(STORE_KEYS.hiddenTxs, '1')
}
const { hidden, handleHiddenBalance, handleHiddenTxs } = usePrivacyContext()

return (
<Screen
Expand Down
4 changes: 3 additions & 1 deletion src/util/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ export async function getInvoiceFromLnurl(address: string, amount: number) {
export function isCashuToken(token: string) {
if (!token || !isStr(token)) { return }
token = token.trim()
const idx = token.indexOf('cashuA')
if (idx !== -1) { token = token.slice(idx) }
const uriPrefixes = [
'https://wallet.nutstash.app/#',
'https://wallet.cashu.me/?token=',
Expand Down Expand Up @@ -224,7 +226,7 @@ export function cleanUpNumericStr(str: string) {
}

export function openUrl(url: string) {
if (!url?.trim()||!isUrl(url)) { return }
if (!url?.trim() || !isUrl(url)) { return }
return Linking.openURL(url)
}

Expand Down
Binary file removed utils/verification/enuts-v0.0.3-beta.apk.sig
Binary file not shown.
Binary file added utils/verification/enuts-v0.0.4-beta.apk.sig
Binary file not shown.
1 change: 1 addition & 0 deletions utils/verification/hash_list.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Not approved by apple store enuts-v0.0.1-beta.apk
a0ad78925f5ba81f0014cd29221ba0f8a15b877189507afdde2675d11c879c0c enuts-v0.0.2-beta.apk
69fc6947e8640d259d1b33e8e658380e4bd8dd648eb368f422ccf420067299c3 enuts-v0.0.3-beta.apk
7cc47301f2fb811205c722b440a0f929451a79e27d693f8b5b1d9fd63788f364 enuts-v0.0.4-beta.apk
8 changes: 4 additions & 4 deletions utils/verification/hash_list.txt.asc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-----BEGIN PGP SIGNATURE-----

iHUEABYIAB0WIQRxIGdR0e37DdxD88y7iol1g7/RhQUCZPsRNwAKCRC7iol1g7/R
hSHeAP9R53nlYl28Jk6Uex0UV9Qo95DodQN4SE+mF0mTQG0uWAD/e00/d2zfBCbz
1qGB0EJcNMocmPXK+GArt0ccFA0sWwI=
=r4GD
iHUEABYIAB0WIQRxIGdR0e37DdxD88y7iol1g7/RhQUCZQ1WAAAKCRC7iol1g7/R
hQ+9AQDDd3cSDmeohltze5Wpw+pUPaFymzmNAHTkbj2ExntlCQD/V+QvkP6cpriR
fXmfuy6YvuDnTph8dtPv3BS9J9cLsgo=
=Gkv9
-----END PGP SIGNATURE-----

0 comments on commit 7cd2462

Please sign in to comment.