From 2d4301d20a34bfd731bdfebf5bb8cef922bbe80b Mon Sep 17 00:00:00 2001 From: ppc Date: Wed, 21 Aug 2024 19:26:12 +0100 Subject: [PATCH] add improved deep linking, server import mode --- amnet-native/App.tsx | 10 +++--- amnet-native/Linking.ts | 36 ++++++++++++++++++++ amnet-native/app/ServerManager.tsx | 54 ++++++++++++++++++++++++++++-- 3 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 amnet-native/Linking.ts diff --git a/amnet-native/App.tsx b/amnet-native/App.tsx index eddeb6f..eb28b85 100644 --- a/amnet-native/App.tsx +++ b/amnet-native/App.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, {useEffect} from "react"; import {StatusBar} from "expo-status-bar"; import {useColorScheme, View} from "react-native"; import {Server, WalletCards} from "lucide-react-native"; @@ -20,6 +20,7 @@ import { } from 'react-native-paper'; import RealmContext from "./models/RealmContext"; +import linking from "./Linking"; import {AMUITabBar} from "./components/AMUITabBar"; import CardAddModal from "./app/CardAddModal"; @@ -99,7 +100,7 @@ export default function AppRoot() { return ( - Starting AMNet... + Starting... ) } @@ -109,15 +110,14 @@ export default function AppRoot() { {/* @ts-ignore */} - + {/* main app */} - + diff --git a/amnet-native/Linking.ts b/amnet-native/Linking.ts new file mode 100644 index 0000000..d5378c1 --- /dev/null +++ b/amnet-native/Linking.ts @@ -0,0 +1,36 @@ +import { getStateFromPath as defaultGetStateFromPath } from '@react-navigation/native'; + +const linking = { + prefixes: ['amnet://', "https://card.ppc.moe/#", "http://card.ppc.moe/#"], + config: { + screens: { + app: { + screens: { + servers: { + screens: { + "server-listing": "/servers", + } + }, + cards: '/cards', + }, + }, + 'add-server': '/servers/add', + 'add-card': '/cards/add', + }, + }, + getStateFromPath: (path, options) => { + const state = defaultGetStateFromPath(path, options); + if (state) { + return { + ...state, + routes: [ + { name: 'app' }, + ...state.routes, + ], + }; + } + return state; + } +}; + +export default linking; \ No newline at end of file diff --git a/amnet-native/app/ServerManager.tsx b/amnet-native/app/ServerManager.tsx index 61cd35b..531f31d 100644 --- a/amnet-native/app/ServerManager.tsx +++ b/amnet-native/app/ServerManager.tsx @@ -1,7 +1,8 @@ +import {BSON} from "realm"; import {Button, Paragraph, useTheme} from "react-native-paper"; import {Globe, History, Plus, ServerOff} from "lucide-react-native"; -import {FlatList, NativeSyntheticEvent, Text, View} from "react-native"; -import React, {useCallback, useLayoutEffect, useMemo, useState} from "react"; +import {Alert, FlatList, NativeSyntheticEvent, Text, View} from "react-native"; +import React, {useCallback, useEffect, useLayoutEffect, useMemo, useState} from "react"; import ContextMenu, {ContextMenuOnPressNativeEvent} from "react-native-context-menu-view"; import {EmptyStatePlaceholder} from "../components/EmptyStatePlaceholder"; import {AMUICard, AMUICardDetail} from "../components/AMUICard"; @@ -9,6 +10,7 @@ import TimeAgo from "../components/TimeAgo"; import RealmContext from "../models/RealmContext"; import {AMServer} from "../models/AMServer"; +import ObjectId = BSON.ObjectId; const {useRealm, useQuery} = RealmContext; @@ -57,7 +59,8 @@ function ServerCard(props: { server: AMServer, navigation: any }) { ) } -export default function ServerManager({navigation}) { +export default function ServerManager({route, navigation}) { + const realm = useRealm(); const theme = useTheme(); const [searchQuery, setSearchQuery] = useState(''); @@ -85,6 +88,11 @@ export default function ServerManager({navigation}) { }) }, [navigation, setSearchQuery]); + // handle deep links once/render + useEffect(() => { + handleDeepLink(realm, navigation, route); + }, []); + if (!servers.length) { return ( @@ -105,4 +113,44 @@ export default function ServerManager({navigation}) { ItemSeparatorComponent={() => } renderItem={i => }/> ) +} + +async function handleDeepLink(realm, navigation, route) { + if (!route.params?.serverAddress) { + return; + } + + let serverId: ObjectId; + + const serverUrl = decodeURIComponent(route.params.serverAddress); + const item = realm.objects(AMServer).filtered("serverAddress = $0", serverUrl); + + if (item.length) { + serverId = item[0]._id; + } else { + try { + new URL(serverUrl); + realm.write(() => { + const newServer = realm.create(AMServer, AMServer.generate(serverUrl)); + newServer.serverName = "Imported Server"; + + serverId = newServer._id; + }); + } catch (TypeError) { + Alert.alert("Invalid Server URL", "The server URL provided is invalid."); + } + } + + // clear param from route + navigation.setParams({serverAddress: null}); + + if (serverId) { + // give it some time to let everything load (and the user sees the initial list) + await new Promise(resolve => setTimeout(resolve, 500)); + navigation.navigate('server', { + serverId: serverId.toHexString() + }); + } + + return null; } \ No newline at end of file