mirror of
https://gitea.tendokyu.moe/ppc/amnet.git
synced 2026-09-25 07:38:17 +03:00
105 lines
4.3 KiB
TypeScript
105 lines
4.3 KiB
TypeScript
import {getGameName} from "amnet-shared";
|
|
import {FlatList, Platform, View} from "react-native";
|
|
import {Button, Text, useTheme} from "react-native-paper";
|
|
import React, {useCallback, useLayoutEffect, useMemo, useState} from "react";
|
|
import {Globe, History, Joystick, Plus, ServerOff} from "lucide-react-native";
|
|
|
|
import TimeAgo from "../components/TimeAgo";
|
|
import {AMUICard, AMUICardDetail} from "../components/AMUICard";
|
|
import {EmptyStatePlaceholder} from "../components/EmptyStatePlaceholder";
|
|
|
|
import {AMServer} from "../models/AMServer";
|
|
import RealmContext from "../models/RealmContext";
|
|
|
|
const {useQuery} = RealmContext;
|
|
|
|
function ServerCard(props: { server: AMServer, navigation: any }) {
|
|
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]);
|
|
|
|
return (
|
|
<AMUICard title={props.server.serverName} onPress={pageCallback}>
|
|
<AMUICardDetail>
|
|
<Globe size={18} color="gray"/>
|
|
<Text variant="bodyMedium" style={{color: "gray", fontFamily: "JetBrainsMono_400Regular"}}>
|
|
{props.server.serverAddress}
|
|
</Text>
|
|
</AMUICardDetail>
|
|
{gameName && (
|
|
<AMUICardDetail>
|
|
<Joystick size={18} color="gray"/>
|
|
<Text variant="bodyMedium" style={{color: "gray"}}>{gameName}</Text>
|
|
</AMUICardDetail>
|
|
)}
|
|
<AMUICardDetail>
|
|
<History size={18} color="gray"/>
|
|
{props.server.lastUsed
|
|
? (<TimeAgo style={{color: "gray"}} dateTo={props.server.lastUsed}/>)
|
|
: (<Text variant="bodyMedium" style={{color: "gray"}}>never</Text>)}
|
|
</AMUICardDetail>
|
|
</AMUICard>
|
|
)
|
|
}
|
|
|
|
export default function ServerManager({navigation}) {
|
|
const theme = useTheme();
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
|
|
const query = useQuery(AMServer);
|
|
const servers = useMemo(() => {
|
|
let q = query;
|
|
|
|
if (searchQuery !== '') {
|
|
q = q.filtered("serverName CONTAINS[c] $0 OR serverAddress CONTAINS[c] $0", searchQuery);
|
|
}
|
|
|
|
return q.sorted("lastUsed", true);
|
|
}, [query, searchQuery]);
|
|
|
|
// enable searchbar
|
|
useLayoutEffect(() => {
|
|
navigation.setOptions({
|
|
headerSearchBarOptions: {
|
|
type: "text",
|
|
value: searchQuery,
|
|
autoCorrect: "none",
|
|
autoCapitalize: "none",
|
|
textColor: theme.colors.onSurface,
|
|
headerIconColor: theme.colors.primary,
|
|
onChangeText: e => setSearchQuery(e.nativeEvent.text)
|
|
},
|
|
})
|
|
}, [navigation, setSearchQuery]);
|
|
|
|
if (!servers.length) {
|
|
return (
|
|
<View style={{gap: 10, flex: 1, justifyContent: "center", alignItems: "center"}}>
|
|
<EmptyStatePlaceholder message="No servers found" icon={<ServerOff color="gray"/>}/>
|
|
{(!searchQuery || !query.length) && (
|
|
<Button mode="text"
|
|
onPress={() => navigation.navigate('add-server')}
|
|
icon={() => <Plus size={18} color={theme.colors.primary}/>}>Add Server</Button>)}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<FlatList contentInsetAdjustmentBehavior="always"
|
|
data={servers}
|
|
keyExtractor={i => i._id.toString()}
|
|
style={{padding: 16, paddingTop: 24}}
|
|
contentContainerStyle={{paddingBottom: 80}}
|
|
renderItem={i => <ServerCard navigation={navigation} server={i.item}/>}
|
|
ItemSeparatorComponent={() => <View style={{height: 15}}/>}
|
|
ListFooterComponent={() => Platform.OS === "ios" ? null : (
|
|
<Button mode="text"
|
|
onPress={() => navigation.navigate('add-server')}
|
|
style={{marginTop: 15, marginBottom: 25}}
|
|
icon={() => <Plus size={18} color={theme.colors.primary}/>}>Add Server</Button>
|
|
)}/>
|
|
)
|
|
} |