feat(lstmobile): intial scanner setup kinda working
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 2m7s
All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 2m7s
This commit is contained in:
38
lstMobile/src/app/(tabs)/_layout.tsx
Normal file
38
lstMobile/src/app/(tabs)/_layout.tsx
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Tabs } from 'expo-router'
|
||||
import React from 'react'
|
||||
import { colors } from '../../stlyes/global'
|
||||
import { Home,Settings } from 'lucide-react-native'
|
||||
|
||||
export default function TabLayout() {
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
tabBarStyle:{
|
||||
|
||||
},
|
||||
tabBarActiveTintColor: 'black',
|
||||
tabBarInactiveTintColor: colors.textSecondary,
|
||||
}}
|
||||
>
|
||||
<Tabs.Screen
|
||||
name='index'
|
||||
options={{
|
||||
title:'Home',
|
||||
tabBarIcon: ({color, size})=>(
|
||||
<Home color={color} size={size}/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name='config'
|
||||
options={{
|
||||
title: 'Config',
|
||||
tabBarIcon: ({color, size})=> (
|
||||
<Settings size={size} color={color}/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Tabs>
|
||||
)
|
||||
}
|
||||
92
lstMobile/src/app/(tabs)/config.tsx
Normal file
92
lstMobile/src/app/(tabs)/config.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
// app/config.tsx
|
||||
import { useEffect, useState } from "react";
|
||||
import { View, Text, TextInput, Button, Alert } from "react-native";
|
||||
import { useRouter } from "expo-router";
|
||||
import { AppConfig, getConfig, saveConfig } from "../../lib/storage";
|
||||
import Constants from "expo-constants";
|
||||
|
||||
export default function Config() {
|
||||
const [serverUrl, setServerUrl] = useState("");
|
||||
const [scannerId, setScannerId] = useState("");
|
||||
const [config, setConfig] = useState<AppConfig | null>(null)
|
||||
const [loading, setLoading] = useState(true);
|
||||
const router = useRouter()
|
||||
|
||||
const version = Constants.expoConfig?.version;
|
||||
const build = Constants.expoConfig?.android?.versionCode ?? 1;
|
||||
|
||||
useEffect(() => {
|
||||
const loadConfig = async () => {
|
||||
const existing = await getConfig();
|
||||
|
||||
if (existing) {
|
||||
setServerUrl(existing.serverUrl);
|
||||
setScannerId(existing.scannerId);
|
||||
setConfig(existing)
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
loadConfig();
|
||||
}, []);
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!serverUrl.trim() || !scannerId.trim()) {
|
||||
Alert.alert("Missing info", "Please fill in both fields.");
|
||||
return;
|
||||
}
|
||||
|
||||
await saveConfig({
|
||||
serverUrl: serverUrl.trim(),
|
||||
scannerId: scannerId.trim(),
|
||||
});
|
||||
|
||||
Alert.alert("Saved", "Config saved to device.");
|
||||
//router.replace("/");
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <Text>Loading config...</Text>;
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1, padding: 16, gap: 12 }}>
|
||||
<View style={{alignItems: "center", margin: 10}}>
|
||||
<Text style={{ fontSize: 20, fontWeight: "600"}}>LST Scanner Config</Text>
|
||||
</View>
|
||||
|
||||
|
||||
<Text>Server IP</Text>
|
||||
<TextInput
|
||||
value={serverUrl}
|
||||
onChangeText={setServerUrl}
|
||||
placeholder="192.168.1.1"
|
||||
autoCapitalize="none"
|
||||
keyboardType="numeric"
|
||||
style={{ borderWidth: 1, padding: 10, borderRadius: 8 }}
|
||||
/>
|
||||
|
||||
<Text>Server port</Text>
|
||||
<TextInput
|
||||
value={scannerId}
|
||||
onChangeText={setScannerId}
|
||||
placeholder="3000"
|
||||
autoCapitalize="characters"
|
||||
keyboardType="numeric"
|
||||
style={{ borderWidth: 1, padding: 10, borderRadius: 8, }}
|
||||
/>
|
||||
|
||||
<View style={{flexDirection: 'row',justifyContent: 'center', padding: 3}}>
|
||||
<Button title="Save Config" onPress={handleSave} />
|
||||
</View>
|
||||
|
||||
|
||||
<View style={{ marginTop: "auto", alignItems: "center", padding: 10 }}>
|
||||
<Text style={{ fontSize: 12, color: "#666" }}>
|
||||
LST Scanner v{version}-{build}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
134
lstMobile/src/app/(tabs)/index.tsx
Normal file
134
lstMobile/src/app/(tabs)/index.tsx
Normal file
@@ -0,0 +1,134 @@
|
||||
import * as Application from "expo-application";
|
||||
import * as Device from "expo-device";
|
||||
import { useRouter } from "expo-router";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
Platform,
|
||||
ScrollView,
|
||||
Text,
|
||||
View,
|
||||
} from "react-native";
|
||||
import HomeHeader from "../../components/HomeHeader";
|
||||
import { type AppConfig, getConfig, hasValidConfig } from "../../lib/storage";
|
||||
import {
|
||||
evaluateVersion,
|
||||
type ServerVersionInfo,
|
||||
type StartupStatus,
|
||||
} from "../../lib/versionValidation";
|
||||
import { globalStyles } from "../../stlyes/global";
|
||||
import axios from 'axios'
|
||||
|
||||
export default function Index() {
|
||||
const [config, setConfig] = useState<AppConfig | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [startupStatus, setStartupStatus] = useState<StartupStatus>({state: "checking"});
|
||||
const [serverInfo, setServerInfo] = useState<ServerVersionInfo>()
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const versionName = Application.nativeApplicationVersion ?? "unknown";
|
||||
const versionCode = Number(Application.nativeBuildVersion ?? "0");
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
|
||||
const startUp = async () => {
|
||||
try {
|
||||
const savedConfig = await getConfig();
|
||||
|
||||
if (!hasValidConfig(savedConfig)) {
|
||||
router.replace("/config");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isMounted) return;
|
||||
setConfig(savedConfig);
|
||||
|
||||
// temp while testing
|
||||
const appBuildCode = 1;
|
||||
|
||||
try {
|
||||
const res = await axios.get(`http://${savedConfig?.serverUrl}:${savedConfig?.scannerId}/lst/api/mobile/version`);
|
||||
console.log(res)
|
||||
const server = (await res.data) as ServerVersionInfo;
|
||||
|
||||
if (!isMounted) return;
|
||||
|
||||
const result = evaluateVersion(appBuildCode, server);
|
||||
setStartupStatus(result);
|
||||
setServerInfo(server)
|
||||
|
||||
if (result.state === "warning") {
|
||||
Alert.alert("Update available", result.message);
|
||||
}
|
||||
} catch {
|
||||
if (!isMounted) return;
|
||||
setStartupStatus({ state: "offline" });
|
||||
}
|
||||
} finally {
|
||||
if (isMounted) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
startUp();
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
|
||||
}, [router]);
|
||||
|
||||
if (loading) {
|
||||
return <Text>Validating Configs.</Text>;
|
||||
}
|
||||
|
||||
if (startupStatus.state === "checking") {
|
||||
return <Text>Checking device and server status...</Text>;
|
||||
}
|
||||
|
||||
if (startupStatus.state === "blocked") {
|
||||
return (
|
||||
<View>
|
||||
<Text>Update Required</Text>
|
||||
<Text>This scanner must be updated before it can be used.</Text>
|
||||
<Text>Scan the update code to continue.</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (startupStatus.state === "offline") {
|
||||
// app still renders, but show disconnected state
|
||||
}
|
||||
|
||||
return (
|
||||
<ScrollView >
|
||||
|
||||
<View style={globalStyles.container}>
|
||||
<HomeHeader />
|
||||
|
||||
<Text>
|
||||
Welcome.{versionName} - {versionCode}
|
||||
</Text>
|
||||
<Text>Running on: {Platform.OS}</Text>
|
||||
<Text>Device model: {Device.modelName}</Text>
|
||||
<Text>Device Brand: {Device.brand}</Text>
|
||||
<Text> OS Version: {Device.osVersion}</Text>
|
||||
<View style={{ flex: 1, padding: 16, gap: 12 }}>
|
||||
<Text style={{ fontSize: 22, fontWeight: "600" }}>Welcome</Text>
|
||||
|
||||
{config ? (
|
||||
<>
|
||||
<Text>Server: {config.serverUrl}</Text>
|
||||
<Text>Scanner: {config.scannerId}</Text>
|
||||
<Text>Server: v{serverInfo?.versionName}</Text>
|
||||
</>
|
||||
) : (
|
||||
<Text>No config found yet.</Text>
|
||||
)}
|
||||
</View></View>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user