mirror of
https://gitea.tendokyu.moe/ppc/amnet.git
synced 2026-09-22 22:28:22 +03:00
move long-press server menu to actual page
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
import {BSON} from "realm";
|
||||
import NfcManager from "react-native-nfc-manager";
|
||||
import React, {useCallback, useEffect, useLayoutEffect, useMemo, useState} from "react";
|
||||
import {Platform, RefreshControl, ScrollView, Share, StyleSheet, Text, View} from "react-native";
|
||||
import {ActivityIndicator, Button, IconButton, Paragraph, Title, useTheme} from "react-native-paper";
|
||||
import {Platform, RefreshControl, ScrollView, Share, StyleSheet, Text, TouchableOpacity, View} from "react-native";
|
||||
import {
|
||||
CircleCheck,
|
||||
CircleDot,
|
||||
CircleEllipsis,
|
||||
CreditCard,
|
||||
Plus,
|
||||
SmartphoneNfcIcon,
|
||||
Share as ShareIcon,
|
||||
WifiOff,
|
||||
TvMinimalPlay,
|
||||
Star,
|
||||
@@ -38,6 +38,7 @@ import {
|
||||
|
||||
import ObjectId = BSON.ObjectId;
|
||||
import {AMCardRecentUse} from "../models/AMCardRecentUse";
|
||||
import {MenuAction, MenuView, NativeActionEvent} from "@react-native-menu/menu";
|
||||
|
||||
const {useRealm, useQuery, useObject} = RealmContext;
|
||||
|
||||
@@ -52,8 +53,24 @@ export default function ServerCardIn({route, navigation}) {
|
||||
query: q => q.sorted("lastUsed", true)
|
||||
});
|
||||
|
||||
// header actions
|
||||
const menuCallback = useCallback((e: NativeActionEvent) => {
|
||||
switch (e.nativeEvent.event) {
|
||||
case "share":
|
||||
Share.share({url: server.shareUrl});
|
||||
break;
|
||||
|
||||
case "delete":
|
||||
realm.write(() => {
|
||||
realm.delete(server);
|
||||
navigation.goBack();
|
||||
});
|
||||
break;
|
||||
}
|
||||
}, [realm, server, navigation]);
|
||||
|
||||
// nfc support
|
||||
const [nfcSupported, setNfcSupported] = useState<boolean | null>(Platform.OS === 'android' ? false : null);
|
||||
const [nfcSupported, setNfcSupported] = useState<boolean | null>(Platform.select({android: false, default: null}));
|
||||
useEffect(() => {
|
||||
if (nfcSupported !== null) {
|
||||
return;
|
||||
@@ -91,30 +108,20 @@ export default function ServerCardIn({route, navigation}) {
|
||||
navigation.setOptions({
|
||||
title: server.serverName,
|
||||
headerRight: () => (
|
||||
<TouchableOpacity onPress={() => Share.share({url: server.shareUrl})}>
|
||||
<ShareIcon color={theme.colors.primary}/>
|
||||
</TouchableOpacity>
|
||||
<MenuView actions={menuActions} onPressAction={menuCallback}>
|
||||
<CircleEllipsis color={theme.colors.primary}/>
|
||||
</MenuView>
|
||||
)
|
||||
});
|
||||
}, [navigation, server]);
|
||||
|
||||
// invalid card/server selection
|
||||
useEffect(() => {
|
||||
if (server?.isValid() !== true) {
|
||||
navigation.goBack();
|
||||
return;
|
||||
}
|
||||
}, [server]);
|
||||
|
||||
useEffect(() => {
|
||||
if (userSelectedCard?.isValid() === false) {
|
||||
setUserSelectedCard(null);
|
||||
}
|
||||
}, [userSelectedCard]);
|
||||
|
||||
// handle auto-refresh
|
||||
useEffect(() => {
|
||||
if (!serverConnectionSuccess || server?.isValid() !== true) {
|
||||
if (!serverConnectionSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -125,6 +132,13 @@ export default function ServerCardIn({route, navigation}) {
|
||||
}
|
||||
}, [serverConnectionSuccess, server]);
|
||||
|
||||
// invalid card/server selection
|
||||
useEffect(() => {
|
||||
if (userSelectedCard?.isValid() === false) {
|
||||
setUserSelectedCard(null);
|
||||
}
|
||||
}, [userSelectedCard]);
|
||||
|
||||
// server info update
|
||||
useEffect(() => {
|
||||
const abortController = new AbortController();
|
||||
@@ -239,8 +253,7 @@ export default function ServerCardIn({route, navigation}) {
|
||||
<View style={styles.container}>
|
||||
<StatusAlert server={server} connectionEstablished={serverConnectionSuccess}/>
|
||||
<View style={styles.section}>
|
||||
<Title
|
||||
style={styles.sectionTitle}>{server.gameId ? `Play ${getGameName(server.gameId)}` : "Selected Card"}</Title>
|
||||
<Title style={styles.sectionTitle}>{server.gameId ? `Play ${getGameName(server.gameId)}` : "Selected Card"}</Title>
|
||||
{selectedCard ? <>
|
||||
<ICCard actionDisabled
|
||||
card={selectedCard}
|
||||
@@ -255,8 +268,7 @@ export default function ServerCardIn({route, navigation}) {
|
||||
mode={serverConnectionSuccess ? "contained" : "outlined"}
|
||||
buttonColor={cardInCompleted === false ? "red" : "green"}
|
||||
onPress={() => cardInCallback(selectedCard)}
|
||||
icon={() => <SquareArrowOutUpRight color={disableCardIn ? "gray" : "white"}
|
||||
size={18}/>}>
|
||||
icon={() => <SquareArrowOutUpRight color={disableCardIn ? "gray" : "white"} size={18}/>}>
|
||||
{cardInCompleted === null ? "Card In" : cardInCompleted ? "Card In Success" : "Failed"}
|
||||
</Button>
|
||||
{nfcSupported === true && (
|
||||
@@ -265,8 +277,7 @@ export default function ServerCardIn({route, navigation}) {
|
||||
disabled={disableCardIn}
|
||||
onPress={performPhysicalCardIn}
|
||||
style={{borderRadius: 10, margin: 0, height: "100%", flex: 0.2}}
|
||||
icon={() => <SmartphoneNfc
|
||||
color={disableCardIn ? "gray" : theme.colors.onBackground} size={18}/>}/>
|
||||
icon={() => <SmartphoneNfc color={disableCardIn ? "gray" : theme.colors.onBackground} size={18}/>}/>
|
||||
)}
|
||||
</View>
|
||||
</>
|
||||
@@ -355,6 +366,28 @@ function DefaultCardDetail() {
|
||||
)
|
||||
}
|
||||
|
||||
const menuActions: MenuAction[] = [
|
||||
{
|
||||
id: "share",
|
||||
title: "Share",
|
||||
image: Platform.select({
|
||||
ios: "square.and.arrow.up",
|
||||
android: "share"
|
||||
})
|
||||
},
|
||||
{
|
||||
id: "delete",
|
||||
title: "Delete Server",
|
||||
attributes: {
|
||||
destructive: true,
|
||||
},
|
||||
image: Platform.select({
|
||||
ios: "trash",
|
||||
android: "delete"
|
||||
})
|
||||
}
|
||||
];
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
section: {
|
||||
gap: 10
|
||||
@@ -367,7 +400,7 @@ const styles = StyleSheet.create({
|
||||
gap: 15
|
||||
},
|
||||
container: {
|
||||
paddingTop: Platform.OS === 'android' ? 120 : 0,
|
||||
paddingTop: Platform.select({android: 120, default: 0}),
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 80,
|
||||
gap: 20
|
||||
|
||||
@@ -1,77 +1,47 @@
|
||||
import {getGameName} from "amnet-shared";
|
||||
import {FlatList, Platform, View} from "react-native";
|
||||
import {Button, Paragraph, useTheme} from "react-native-paper";
|
||||
import React, {useCallback, useLayoutEffect, useMemo, useState} from "react";
|
||||
import {Globe, History, Joystick, Plus, ServerOff} from "lucide-react-native";
|
||||
import {FlatList, NativeSyntheticEvent, Platform, ScrollView, Share, View} from "react-native";
|
||||
import ContextMenu, {ContextMenuOnPressNativeEvent} from "react-native-context-menu-view";
|
||||
import {EmptyStatePlaceholder} from "../components/EmptyStatePlaceholder";
|
||||
import {AMUICard, AMUICardDetail} from "../components/AMUICard";
|
||||
|
||||
import TimeAgo from "../components/TimeAgo";
|
||||
import {AMUICard, AMUICardDetail} from "../components/AMUICard";
|
||||
import {EmptyStatePlaceholder} from "../components/EmptyStatePlaceholder";
|
||||
|
||||
import RealmContext from "../models/RealmContext";
|
||||
import {AMServer} from "../models/AMServer";
|
||||
import {getGameName} from "amnet-shared";
|
||||
import RealmContext from "../models/RealmContext";
|
||||
|
||||
const {useRealm, useQuery} = RealmContext;
|
||||
const {useQuery} = RealmContext;
|
||||
|
||||
function ServerCard(props: { server: AMServer, navigation: any }) {
|
||||
const realm = useRealm();
|
||||
const gameName = useMemo(() => getGameName(props.server.gameId), [props.server.gameId]);
|
||||
|
||||
const pageCallback = useCallback(() => {
|
||||
props.navigation.navigate('server', {
|
||||
serverId: props.server._id.toHexString()
|
||||
});
|
||||
}, [props.navigation, props.server]);
|
||||
|
||||
const pageContextMenuCallback = useCallback((action: NativeSyntheticEvent<ContextMenuOnPressNativeEvent>) => {
|
||||
switch (action.nativeEvent.indexPath.toString()) {
|
||||
case "0":
|
||||
pageCallback();
|
||||
return;
|
||||
|
||||
case "1,0":
|
||||
Share.share({url: props.server.shareUrl});
|
||||
return;
|
||||
|
||||
case "1,1":
|
||||
realm.write(() => realm.delete(props.server));
|
||||
return;
|
||||
}
|
||||
}, [realm, props.server]);
|
||||
|
||||
return (
|
||||
<ContextMenu onPress={pageContextMenuCallback} actions={[
|
||||
{title: `Select ${props.server.serverName}`, systemIcon: "chevron.right"},
|
||||
{
|
||||
title: Platform.OS === "ios" ? "" : "Additional Actions",
|
||||
inlineChildren: true,
|
||||
actions: [
|
||||
{title: "Share Server", systemIcon: "square.and.arrow.up"},
|
||||
{title: "Delete Server", systemIcon: "trash", destructive: true}
|
||||
]
|
||||
}
|
||||
]}>
|
||||
<AMUICard title={props.server.serverName} onPress={pageCallback} onLongPress={() => {}}>
|
||||
<AMUICard title={props.server.serverName} onPress={pageCallback}>
|
||||
<AMUICardDetail>
|
||||
<Globe size={18} color="gray"/>
|
||||
<Paragraph style={{color: "gray", fontFamily: "JetBrainsMono_400Regular"}}>
|
||||
{props.server.serverAddress}
|
||||
</Paragraph>
|
||||
</AMUICardDetail>
|
||||
{gameName && (
|
||||
<AMUICardDetail>
|
||||
<Globe size={18} color="gray"/>
|
||||
<Paragraph style={{color: "gray", fontFamily: "JetBrainsMono_400Regular"}}>
|
||||
{props.server.serverAddress}
|
||||
</Paragraph>
|
||||
<Joystick size={18} color="gray"/>
|
||||
<Paragraph style={{color: "gray"}}>{gameName}</Paragraph>
|
||||
</AMUICardDetail>
|
||||
{gameName && (
|
||||
<AMUICardDetail>
|
||||
<Joystick size={18} color="gray"/>
|
||||
<Paragraph style={{color: "gray"}}>{gameName}</Paragraph>
|
||||
</AMUICardDetail>
|
||||
)}
|
||||
<AMUICardDetail>
|
||||
<History size={18} color="gray"/>
|
||||
{props.server.lastUsed
|
||||
? (<TimeAgo style={{color: "gray"}} dateTo={props.server.lastUsed}/>)
|
||||
: (<Paragraph style={{color: "gray"}}>never</Paragraph>)}
|
||||
</AMUICardDetail>
|
||||
</AMUICard>
|
||||
</ContextMenu>
|
||||
)}
|
||||
<AMUICardDetail>
|
||||
<History size={18} color="gray"/>
|
||||
{props.server.lastUsed
|
||||
? (<TimeAgo style={{color: "gray"}} dateTo={props.server.lastUsed}/>)
|
||||
: (<Paragraph style={{color: "gray"}}>never</Paragraph>)}
|
||||
</AMUICardDetail>
|
||||
</AMUICard>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Generated
+14
-3
@@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.0",
|
||||
"@expo-google-fonts/jetbrains-mono": "^0.2.3",
|
||||
"@react-native-menu/menu": "^1.2.3",
|
||||
"@react-navigation/bottom-tabs": "^7.3.3",
|
||||
"@react-navigation/native": "^7.0.19",
|
||||
"@react-navigation/native-stack": "^7.3.3",
|
||||
@@ -3456,6 +3457,16 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-menu/menu": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-menu/menu/-/menu-1.2.3.tgz",
|
||||
"integrity": "sha512-sEfiVIivsa0lSelFm9Wbm/RAi+XoEHc75GGhjwvSrj9KSCVvNNXwr9F8l42e1t/lzYvVYzmkYxLG6VKxrDYJiw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native/assets-registry": {
|
||||
"version": "0.76.8",
|
||||
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.76.8.tgz",
|
||||
@@ -7252,9 +7263,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/image-size": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.0.tgz",
|
||||
"integrity": "sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
|
||||
"integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"queue": "6.0.2"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.27.0",
|
||||
"@expo-google-fonts/jetbrains-mono": "^0.2.3",
|
||||
"@react-native-menu/menu": "^1.2.3",
|
||||
"@react-navigation/bottom-tabs": "^7.3.3",
|
||||
"@react-navigation/native": "^7.0.19",
|
||||
"@react-navigation/native-stack": "^7.3.3",
|
||||
|
||||
Reference in New Issue
Block a user