mirror of
https://gitea.tendokyu.moe/ppc/amnet.git
synced 2026-09-22 22:28:22 +03:00
add server listing, create modal
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import {useCallback, useEffect, useState} from "react";
|
||||
import {Card, Paragraph, useTheme} from "react-native-paper";
|
||||
import {TextInput, TouchableOpacity, View} from "react-native";
|
||||
import {useModalStyles} from "../utils/ModalStyles";
|
||||
|
||||
import RealmContext from "../models/RealmContext";
|
||||
import {AMServer} from "../models/AMServer";
|
||||
|
||||
const {useRealm} = RealmContext;
|
||||
|
||||
export default function ServerAddModal({navigation}) {
|
||||
const realm = useRealm();
|
||||
const theme = useTheme();
|
||||
const modalStyles = useModalStyles();
|
||||
|
||||
const [serverAddress, setServerAddress] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerLeft: () => <TouchableOpacity onPress={() => navigation.goBack()}>
|
||||
<Paragraph style={modalStyles.headerText}>Cancel</Paragraph>
|
||||
</TouchableOpacity>,
|
||||
});
|
||||
}, [navigation, modalStyles]);
|
||||
|
||||
useEffect(() => {
|
||||
let urlValid = false;
|
||||
|
||||
try {
|
||||
new URL(serverAddress);
|
||||
urlValid = true;
|
||||
} catch {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
const themeOptions = urlValid ? modalStyles.headerText : {color: theme.colors.outline};
|
||||
|
||||
navigation.setOptions({
|
||||
headerRight: () => <TouchableOpacity disabled={!urlValid} onPress={() => saveServer()}>
|
||||
<Paragraph style={{...themeOptions, fontWeight: "600"}}>Save</Paragraph>
|
||||
</TouchableOpacity>
|
||||
})
|
||||
}, [navigation, modalStyles, serverAddress]);
|
||||
|
||||
const saveServer = useCallback(() => {
|
||||
let serverObject = realm.objects<AMServer>("server").find(x => x.serverAddress == serverAddress);
|
||||
if (!serverObject) {
|
||||
realm.write(() => {
|
||||
serverObject = realm.create<AMServer>("server", AMServer.generate(serverAddress));
|
||||
});
|
||||
}
|
||||
|
||||
navigation.goBack();
|
||||
setTimeout(() => navigation.navigate('server-card-in', {
|
||||
serverId: serverObject._id.toHexString()
|
||||
}), 500);
|
||||
}, [serverAddress, realm]);
|
||||
|
||||
return (<View style={{display: "flex", gap: 10, justifyContent: "center", paddingHorizontal: 15, paddingTop: 25}}>
|
||||
<Card>
|
||||
<Card.Content>
|
||||
<View style={{...modalStyles.formItemRow, gap: 10}}>
|
||||
<Paragraph style={{...modalStyles.formItemName, minWidth: 0}}>
|
||||
Address
|
||||
</Paragraph>
|
||||
<TextInput style={modalStyles.formItemInput}
|
||||
autoFocus
|
||||
numberOfLines={1}
|
||||
autoComplete="off"
|
||||
textContentType="URL"
|
||||
autoCapitalize="none"
|
||||
value={serverAddress}
|
||||
onChangeText={setServerAddress}
|
||||
placeholder="http://192.168.1.2:6070"
|
||||
placeholderTextColor={theme.colors.outline}/>
|
||||
</View>
|
||||
</Card.Content>
|
||||
</Card>
|
||||
|
||||
<Paragraph style={modalStyles.formFootnote}>
|
||||
If you're using HTTPS, ensure a trusted certificate has been configured via HTTP.SYS
|
||||
</Paragraph>
|
||||
</View>)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import {ScrollView} from "react-native";
|
||||
|
||||
export default function ServerCardIn({navigation}) {
|
||||
return (
|
||||
<ScrollView contentInsetAdjustmentBehavior="always">
|
||||
|
||||
</ScrollView>
|
||||
)
|
||||
}
|
||||
@@ -1,9 +1,61 @@
|
||||
import {Text, View} from "react-native";
|
||||
import {Paragraph} from "react-native-paper";
|
||||
import React, {useCallback, useMemo} from "react";
|
||||
import {FlatList, Text, View} from "react-native";
|
||||
import {Globe, History, ServerOff} from "lucide-react-native";
|
||||
import {EmptyStatePlaceholder} from "../components/EmptyStatePlaceholder";
|
||||
import {AMUICard, AMUICardDetail} from "../components/AMUICard";
|
||||
import TimeAgo from "../components/TimeAgo";
|
||||
|
||||
import RealmContext from "../models/RealmContext";
|
||||
import {AMServer} from "../models/AMServer";
|
||||
|
||||
const {useQuery} = RealmContext;
|
||||
|
||||
function ServerCard(props: { server: AMServer, navigation: any }) {
|
||||
const pageCallback = useCallback(() => {
|
||||
props.navigation.navigate('server-card-in', {
|
||||
serverId: props.server._id.toHexString()
|
||||
});
|
||||
}, [props.navigation, props.server]);
|
||||
|
||||
export default function ServerManager() {
|
||||
return (
|
||||
<View>
|
||||
<Text>Server Manager</Text>
|
||||
</View>
|
||||
);
|
||||
<AMUICard title={props.server.serverName} onPress={pageCallback}>
|
||||
<AMUICardDetail>
|
||||
<Globe size={18} color="gray"/>
|
||||
<Text style={{color: "gray", fontFamily: "JetBrainsMono_400Regular"}}>
|
||||
{props.server.serverAddress}
|
||||
</Text>
|
||||
</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>
|
||||
)
|
||||
}
|
||||
|
||||
export default function ServerManager({navigation}) {
|
||||
const query = useQuery(AMServer);
|
||||
const servers = useMemo(() => query.sorted("lastUsed"), [query]);
|
||||
|
||||
if (!servers.length) {
|
||||
return (
|
||||
<View style={{display: "flex", flex: 1, gap: 15, justifyContent: "center", alignItems: "center"}}>
|
||||
<EmptyStatePlaceholder message="No servers added yet" icon={<ServerOff color="gray"/>}/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<FlatList contentInsetAdjustmentBehavior="always"
|
||||
style={{padding: 16, paddingTop: 24}}
|
||||
data={servers}
|
||||
keyExtractor={i => i._id.toString()}
|
||||
contentContainerStyle={{paddingBottom: 40}}
|
||||
ItemSeparatorComponent={() => <View style={{height: 15}}/>}
|
||||
renderItem={i => <ServerCard navigation={navigation} server={i.item}/>}/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import {Plus} from "lucide-react-native";
|
||||
import {TouchableOpacity} from "react-native";
|
||||
import {useTheme} from "@react-navigation/native";
|
||||
import {createNativeStackNavigator} from "@react-navigation/native-stack";
|
||||
|
||||
import ServerCardIn from "./ServerCardIn";
|
||||
import ServerManager from "./ServerManager";
|
||||
import ServerAddModal from "./ServerAddModal";
|
||||
|
||||
const Stack = createNativeStackNavigator();
|
||||
|
||||
export default function ServerManagerStack({navigation}) {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<Stack.Navigator>
|
||||
<Stack.Group screenOptions={{
|
||||
headerLargeTitle: true,
|
||||
headerBlurEffect: "regular",
|
||||
headerStyle: {
|
||||
backgroundColor: theme.colors.background
|
||||
}
|
||||
}}>
|
||||
<Stack.Screen name="server-listing"
|
||||
component={ServerManager}
|
||||
options={{
|
||||
title: "Servers",
|
||||
headerRight: () => <TouchableOpacity
|
||||
onPress={() => navigation.navigate('add-server')}>
|
||||
<Plus/>
|
||||
</TouchableOpacity>
|
||||
}}/>
|
||||
|
||||
<Stack.Screen name="server-card-in" options={{title: "Server"}} component={ServerCardIn}/>
|
||||
</Stack.Group>
|
||||
|
||||
<Stack.Group screenOptions={{presentation: "modal"}}>
|
||||
<Stack.Screen name="add-server" component={ServerAddModal} options={{title: "Add Server"}}/>
|
||||
</Stack.Group>
|
||||
</Stack.Navigator>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user