diff --git a/amnet-native/app/ServerCardIn.tsx b/amnet-native/app/ServerCardIn.tsx index 46ca4da..6e012bd 100644 --- a/amnet-native/app/ServerCardIn.tsx +++ b/amnet-native/app/ServerCardIn.tsx @@ -3,8 +3,16 @@ import React, {useCallback, useEffect, useLayoutEffect, useMemo, useState} from import {ActivityIndicator, Button, Paragraph, Title, useTheme} from "react-native-paper"; import {Alert, RefreshControl, ScrollView, Share, StyleSheet, Text, TouchableOpacity, View} from "react-native"; import { - CircleCheck, CircleDot, CreditCard, Nfc, Plus, SmartphoneNfcIcon, - Share as ShareIcon, WifiOff, TvMinimalPlay, Star + CircleCheck, + CircleDot, + CreditCard, + Nfc, + Plus, + SmartphoneNfcIcon, + Share as ShareIcon, + WifiOff, + TvMinimalPlay, + Star } from "lucide-react-native"; import {EmptyStatePlaceholder} from "../components/EmptyStatePlaceholder"; @@ -30,40 +38,24 @@ export default function ServerCardIn({route, navigation}) { const realm = useRealm(); const theme = useTheme(); - // card listing state + let {serverId} = route.params; + const server = useObject(AMServer, ObjectId.createFromHexString(serverId)); const cards = useQuery({ type: AMCard, query: q => q.sorted("lastUsed", true) }); - const [defaultCard, setDefaultCard] = useState(null); - const [selectedCard, setSelectedCard] = useState(null); - const [cardInCompleted, setCardInCompleted] = useState(null); - - const unselectedCards = useMemo(() => { - // protect against selected card being removed - switch (selectedCard?.isValid()) { - case true: - return cards.filter(x => !x._id.equals(selectedCard._id)); - - // clear out invalid - case false: - setSelectedCard(null); - return cards; - - default: - return cards; - } - }, [cards, selectedCard]); - // server state const [serverRefreshing, setServerRefreshing] = useState(false); const [serverReloadCounter, setServerReloadCounter] = useState(0); - const [serverPreviousGameId, setServerPreviousGameId] = useState(null); const [connectionTestResult, setConnectionTestResult] = useState(null); - let {serverId} = route.params; - const server = useObject(AMServer, ObjectId.createFromHexString(serverId)); + const [userSelectedCard, setUserSelectedCard] = useState(null); + const [cardInCompleted, setCardInCompleted] = useState(null); + + const defaultCard = useMemo(() => cards.find(x => x.lastUsedGameId === server.gameId), [cards, server.gameId]); + const selectedCard = useMemo(() => userSelectedCard ?? defaultCard ?? cards.at(1) ?? null, [userSelectedCard, defaultCard]); + const unselectedCards = useMemo(() => cards.filter(x => x._id.toHexString() !== selectedCard?._id.toHexString()), [cards, selectedCard]); useLayoutEffect(() => { if (server?.isValid() !== true) { @@ -80,7 +72,27 @@ export default function ServerCardIn({route, navigation}) { }); }, [navigation, server]); - // card selection, server connection checks + // invalid card selection + useEffect(() => { + if (userSelectedCard?.isValid() === false) { + setUserSelectedCard(null); + } + }, [userSelectedCard]); + + // auto-refresh + useEffect(() => { + if (!connectionTestResult) { + return; + } + + const metrics = server as AMServerInstanceMetrics; + if (metrics.sessionUptime > 0 && metrics.timeSinceLastPoll === null) { + const timeout = setTimeout(() => setServerReloadCounter(serverReloadCounter + 1), 5000); + return () => clearTimeout(timeout); + } + }, [connectionTestResult, server]); + + // server info update useEffect(() => { if (server?.isValid() !== true) { navigation.goBack(); @@ -92,15 +104,6 @@ export default function ServerCardIn({route, navigation}) { return; } - if (defaultCard?.isValid() === false) { - setDefaultCard(null); - } - - // select a card if there's none selected - if (selectedCard?.isValid() !== true) { - setSelectedCard(cards.length ? cards[0] : null); - } - const abortController = new AbortController(); fetchServerInfo(server.serverAddress, abortController.signal).then(r => { if (!r) { @@ -109,20 +112,11 @@ export default function ServerCardIn({route, navigation}) { } setConnectionTestResult(true); + realm.write(() => { server.lastUsed = new Date(); Object.keys(r).forEach(x => server[x] = r[x]); }); - - const matchingGameCard = cards.find(x => x.lastUsedGameId === server.gameId); - if (matchingGameCard) { - setDefaultCard(matchingGameCard); - } - - if (server.gameId !== serverPreviousGameId) { - setServerPreviousGameId(server.gameId); - setSelectedCard(matchingGameCard || cards[0]); - } }).catch(() => { setConnectionTestResult(false); }).finally(() => { @@ -136,7 +130,6 @@ export default function ServerCardIn({route, navigation}) { } }, [serverId, serverReloadCounter, realm]); - // card in callback const cardInCallback = useCallback(() => { setCardInCompleted(false); @@ -149,11 +142,6 @@ export default function ServerCardIn({route, navigation}) { selectedCard.lastUsedGameId = server.gameId; }); - // set default card if there's a game id provided by the server - if (server.gameId) { - setDefaultCard(selectedCard); - } - setCardInCompleted(r); }).catch(() => { setCardInCompleted(false); @@ -168,7 +156,7 @@ export default function ServerCardIn({route, navigation}) { const performRefresh = () => { setServerRefreshing(true); setServerReloadCounter(serverReloadCounter + 1); - } + }; const gameName = useMemo(() => getGameName(server.gameId), [server.gameId]); const disableCardIn = useMemo(() => cardInCompleted !== null || !connectionTestResult, [cardInCompleted, connectionTestResult]); @@ -232,11 +220,12 @@ export default function ServerCardIn({route, navigation}) { } - onPress={() => setSelectedCard(card)}> + onPress={() => setUserSelectedCard(card)}> {defaultCard?.code == card.code && } )) : - }/> + }/> } )}