Modals finally work

This commit is contained in:
Joshua Higgins
2025-04-19 15:08:24 -04:00
parent 567791df7e
commit 40fb1aabb1
5 changed files with 136 additions and 83 deletions

View File

@@ -6,9 +6,9 @@ export * from 'expo-router';
declare module 'expo-router' { declare module 'expo-router' {
export namespace ExpoRouter { export namespace ExpoRouter {
export interface __routes<T extends string | object = string> { export interface __routes<T extends string | object = string> {
hrefInputParams: { pathname: Router.RelativePathString, params?: Router.UnknownInputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownInputParams } | { pathname: `/`; params?: Router.UnknownInputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownInputParams; }; hrefInputParams: { pathname: Router.RelativePathString, params?: Router.UnknownInputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownInputParams } | { pathname: `/createComputer`; params?: Router.UnknownInputParams; } | { pathname: `/createServer`; params?: Router.UnknownInputParams; } | { pathname: `/`; params?: Router.UnknownInputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownInputParams; };
hrefOutputParams: { pathname: Router.RelativePathString, params?: Router.UnknownOutputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownOutputParams } | { pathname: `/`; params?: Router.UnknownOutputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownOutputParams; }; hrefOutputParams: { pathname: Router.RelativePathString, params?: Router.UnknownOutputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownOutputParams } | { pathname: `/createComputer`; params?: Router.UnknownOutputParams; } | { pathname: `/createServer`; params?: Router.UnknownOutputParams; } | { pathname: `/`; params?: Router.UnknownOutputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownOutputParams; };
href: Router.RelativePathString | Router.ExternalPathString | `/${`?${string}` | `#${string}` | ''}` | `/_sitemap${`?${string}` | `#${string}` | ''}` | { pathname: Router.RelativePathString, params?: Router.UnknownInputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownInputParams } | { pathname: `/`; params?: Router.UnknownInputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownInputParams; }; href: Router.RelativePathString | Router.ExternalPathString | `/createComputer${`?${string}` | `#${string}` | ''}` | `/createServer${`?${string}` | `#${string}` | ''}` | `/${`?${string}` | `#${string}` | ''}` | `/_sitemap${`?${string}` | `#${string}` | ''}` | { pathname: Router.RelativePathString, params?: Router.UnknownInputParams } | { pathname: Router.ExternalPathString, params?: Router.UnknownInputParams } | { pathname: `/createComputer`; params?: Router.UnknownInputParams; } | { pathname: `/createServer`; params?: Router.UnknownInputParams; } | { pathname: `/`; params?: Router.UnknownInputParams; } | { pathname: `/_sitemap`; params?: Router.UnknownInputParams; };
} }
} }
} }

View File

@@ -1,5 +1,65 @@
import { Stack } from "expo-router"; import {Stack, useRouter} from "expo-router";
import {Text, TouchableOpacity, View} from "react-native";
import {iOS_HIGHLIGHT} from "@/app/index";
export default function RootLayout() { export default function RootLayout() {
return <Stack />; const router = useRouter();
return (
<>
<Stack>
<Stack.Screen name="index" />
<Stack.Screen name="createComputer" options={{
presentation: 'modal',
title: 'Add a Computer',
headerLeft: props => <Cancel />,
headerRight: props =>
<View>
<TouchableOpacity
onPress={(event) => {
//TODO: Save to DB
router.navigate('../');
}}>
<Text style={{
color: iOS_HIGHLIGHT,
fontWeight: 'bold',
}}>Save</Text>
</TouchableOpacity>
</View>
}} />
<Stack.Screen name="createServer" options={{
presentation: 'modal',
title: 'Add a WoL Server',
headerLeft: props => <Cancel />,
headerRight: props =>
<View>
<TouchableOpacity
onPress={(event) => {
//TODO: Save to DB
router.navigate('../');
}}>
<Text style={{
color: iOS_HIGHLIGHT,
fontWeight: 'bold',
}}>Save</Text>
</TouchableOpacity>
</View>
}} />
</Stack>
</>
);
}
function Cancel() {
const router = useRouter();
return <View>
<TouchableOpacity
onPress={(event) => {
router.navigate('../');
}}>
<Text style={{ color: 'red'}}>Cancel</Text>
</TouchableOpacity>
</View>
} }

14
app/createComputer.tsx Normal file
View File

@@ -0,0 +1,14 @@
import {Text, View} from "react-native";
import {MenuView} from "@react-native-menu/menu";
import {ChevronDown, Plus} from "lucide-react-native";
import {Stack} from "expo-router";
export default function CreateComputer() {
return (
<View>
<Text>Hello</Text>
</View>
);
}

11
app/createServer.tsx Normal file
View File

@@ -0,0 +1,11 @@
import {Text, View} from "react-native";
export default function CreateServer() {
return (
<View>
<Text>Hello</Text>
</View>
);
}

View File

@@ -1,59 +1,15 @@
import { Stack } from "expo-router"; import {Href, Stack, useRouter} from "expo-router";
import {StyleSheet, Text, View, ColorValue, ListRenderItemInfo, TouchableOpacity, Platform} from "react-native"; import {StyleSheet, Text, View, ColorValue, ListRenderItemInfo, TouchableOpacity, Platform, Modal} from "react-native";
import {RowMap, SwipeListView} from "react-native-swipe-list-view"; import {RowMap, SwipeListView} from "react-native-swipe-list-view";
import {ChevronDown, Plus} from "lucide-react-native"; import {ChevronDown, Plus} from "lucide-react-native";
import {useEffect, useState} from "react"; import {useEffect, useState} from "react";
import {MenuAction, MenuView, NativeActionEvent} from "@react-native-menu/menu"; import {MenuAction, MenuView, NativeActionEvent} from "@react-native-menu/menu";
import {SQLiteDatabase, SQLiteProvider, useSQLiteContext} from "expo-sqlite"; import {SQLiteDatabase, SQLiteProvider, useSQLiteContext} from "expo-sqlite";
import CreateComputer from "@/app/createComputer";
const servers: Server[] = [ export const iOS_HIGHLIGHT = "#007AFF";
{
key: 0,
name: "Test Data Server",
domain: "localhost",
},
{
key: 1,
name: "The Other Server",
domain: "192.168.86.252",
}
];
const computers: Computer[] = [
{
key: 0,
server_key: 0,
name: "Test PC",
emoji: "💻",
background_color: '#D9D9D9',
mac_address: "00:1A:2B:3C:4D:5E",
},
{
key: 1,
server_key: 0,
name: "Another PC in the basement",
emoji: "💻",
background_color: '#D9D9D9',
mac_address: "00:1A:2B:3C:4D:5E",
},
{
key: 2,
server_key: 1,
name: "Mom's PC",
emoji: "🌹",
background_color: '#D9D9D9',
mac_address: "00:1A:2B:3C:4D:5E",
},
{
key: 3,
server_key: 1,
name: "Jordan's PC",
emoji: "💪",
background_color: '#D9D9D9',
mac_address: "00:1A:2B:3C:4D:5E",
}
];
async function migrateDbIfNeeded(db: SQLiteDatabase) { export async function migrateDbIfNeeded(db: SQLiteDatabase) {
await db.execAsync(` await db.execAsync(`
PRAGMA journal_mode = WAL; PRAGMA journal_mode = WAL;
CREATE TABLE IF NOT EXISTS servers (key INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, domain TEXT NOT NULL); CREATE TABLE IF NOT EXISTS servers (key INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, domain TEXT NOT NULL);
@@ -98,14 +54,25 @@ function Header(props: { servers: Server[], setServers: (value: (((prevState: Se
setup(); setup();
}, []); }, []);
const [ menuEvent, setMenuEvent ] = useState("");
const router = useRouter();
useEffect(() => {
if (menuEvent === "addComputer") {
router.navigate('/createComputer');
} else if (menuEvent === "addServer") {
router.navigate('/createServer');
}
setMenuEvent("");
}, [menuEvent]);
const selectActions: MenuAction[] = []; const selectActions: MenuAction[] = [];
for (const server of props.servers) { for (const server of props.servers) {
if (server.name !== props.currentServerName) { if (server.name !== props.currentServerName) {
selectActions.push({ selectActions.push({
id: server.domain, id: server.domain,
title: server.name, title: server.name,
titleColor: '#2367A2', titleColor: '#000000',
imageColor: '#2367A2', imageColor: '#000000',
}) })
} }
} }
@@ -130,6 +97,25 @@ function Header(props: { servers: Server[], setServers: (value: (((prevState: Se
props.setCurrentServerName(newName?.name ?? "None"); props.setCurrentServerName(newName?.name ?? "None");
}; };
const addActions: MenuAction[] = [
{
id: 'addServer',
title: 'Add WoL Server',
titleColor: '#000000',
image: 'globe',
imageColor: '#000000',
}
];
if (props.currentServerName !== "None") {
addActions.push({
id: 'addComputer',
title: 'Add Computer',
titleColor: '#000000',
image: 'desktopcomputer',
imageColor: '#000000',
});
}
return <Stack.Screen return <Stack.Screen
options={{ options={{
title: 'Home', title: 'Home',
@@ -147,43 +133,25 @@ function Header(props: { servers: Server[], setServers: (value: (((prevState: Se
fontSize: 20, fontSize: 20,
fontWeight: 'bold', fontWeight: 'bold',
}}>{props.currentServerName}</Text> }}>{props.currentServerName}</Text>
{selectActions.length > 1 && {props.servers.length > 0 &&
<View style={{ <View style={{
backgroundColor: "#007AFF", backgroundColor: iOS_HIGHLIGHT,
borderRadius: 100, borderRadius: 100,
}}> }}>
<MenuView onPressAction={handleServerSelect} actions={selectActions}> <MenuView onPressAction={handleServerSelect} actions={selectActions}>
<ChevronDown color={"#FFFFFF"}/> <ChevronDown color={"#FFFFFF"}/>
</MenuView> </MenuView>
</View> </View>
} }
</View>, </View>,
headerRight: props => headerRight: props =>
<View> <View>
<MenuView <MenuView
onPressAction={({nativeEvent}) => { onPressAction={({nativeEvent}) => { setMenuEvent(nativeEvent.event); }}
console.log(JSON.stringify(nativeEvent)); actions={addActions}
//TODO: Handle adding computers/servers
}}
actions={[
{
id: 'addComputer',
title: 'Add Computer',
titleColor: '#000000',
image: 'desktopcomputer',
imageColor: '#000000',
},
{
id: 'addServer',
title: 'Add Server',
titleColor: '#000000',
image: 'globe',
imageColor: '#000000',
},
]}
shouldOpenOnLongPress={false} shouldOpenOnLongPress={false}
> >
<Plus color={"#007AFF"}/> <Plus color={iOS_HIGHLIGHT}/>
</MenuView> </MenuView>
</View> </View>
}} }}