feat: new name and icon
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# UpSnap Mobile
|
# Jumpstart - Client for UpSnap
|
||||||
|
|
||||||
A React Native Expo app that connects to an UpSnap server and provides mobile access to all Wake-on-LAN features.
|
A React Native Expo app that connects to an UpSnap server and provides mobile access to all Wake-on-LAN features.
|
||||||
|
|
||||||
|
|||||||
2
app.json
2
app.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"expo": {
|
"expo": {
|
||||||
"name": "Remote WoL",
|
"name": "Jumpstart",
|
||||||
"slug": "remote-wol",
|
"slug": "remote-wol",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"orientation": "portrait",
|
"orientation": "portrait",
|
||||||
|
|||||||
@@ -1,250 +1,231 @@
|
|||||||
import React from "react";
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
TouchableOpacity,
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} from "react-native";
|
} from 'react-native';
|
||||||
import { useColorScheme } from "../../hooks/use-color-scheme";
|
import { useColorScheme } from '../../hooks/use-color-scheme';
|
||||||
import { useAuth } from "../../src/context/AuthContext";
|
import { useAuth } from '../../src/context/AuthContext';
|
||||||
import { useRouter } from "expo-router";
|
import { useRouter } from 'expo-router';
|
||||||
|
import Constants from 'expo-constants';
|
||||||
|
|
||||||
export default function SettingsScreen() {
|
export default function SettingsScreen() {
|
||||||
const { user, serverAddress, logout } = useAuth();
|
const { user, serverAddress, logout } = useAuth();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const colorScheme = useColorScheme() ?? "light";
|
const colorScheme = useColorScheme() ?? 'light';
|
||||||
const isDark = colorScheme === "dark";
|
const isDark = colorScheme === 'dark';
|
||||||
const bgColor = isDark ? "#0b0b0d" : "#f5f5f5";
|
const bgColor = isDark ? '#0b0b0d' : '#f5f5f5';
|
||||||
const sectionBg = isDark ? "#1c1c1e" : "#fff";
|
const sectionBg = isDark ? '#1c1c1e' : '#fff';
|
||||||
const sectionTitleBg = isDark ? "#111111" : "#f9f9f9";
|
const sectionTitleBg = isDark ? '#111111' : '#f9f9f9';
|
||||||
const textColor = isDark ? "#fff" : "#333";
|
const textColor = isDark ? '#fff' : '#333';
|
||||||
const subTextColor = isDark ? "#c6c6c8" : "#666";
|
const subTextColor = isDark ? '#c6c6c8' : '#666';
|
||||||
const primary = isDark ? "#0A84FF" : "#007AFF";
|
const primary = isDark ? '#0A84FF' : '#007AFF';
|
||||||
const destructiveColor = "#f44336";
|
const destructiveColor = '#f44336';
|
||||||
|
|
||||||
const handleLogout = () => {
|
const handleLogout = () => {
|
||||||
Alert.alert("Logout", "Are you sure you want to logout?", [
|
Alert.alert('Logout', 'Are you sure you want to logout?', [
|
||||||
{ text: "Cancel", style: "cancel" },
|
{ text: 'Cancel', style: 'cancel' },
|
||||||
{
|
{
|
||||||
text: "Logout",
|
text: 'Logout',
|
||||||
style: "destructive",
|
style: 'destructive',
|
||||||
onPress: async () => {
|
onPress: async () => {
|
||||||
router.replace("/login");
|
router.replace('/login');
|
||||||
await logout();
|
await logout();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingItem = ({
|
const SettingItem = ({
|
||||||
label,
|
label,
|
||||||
value,
|
value,
|
||||||
onPress,
|
onPress,
|
||||||
}: {
|
}: {
|
||||||
label: string;
|
label: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
onPress?: () => void;
|
onPress?: () => void;
|
||||||
}) => (
|
}) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[
|
style={[
|
||||||
styles.settingItem,
|
styles.settingItem,
|
||||||
{ borderBottomColor: isDark ? "rgba(255,255,255,0.03)" : "#f0f0f0" },
|
{ borderBottomColor: isDark ? 'rgba(255,255,255,0.03)' : '#f0f0f0' },
|
||||||
]}
|
]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
disabled={!onPress}
|
disabled={!onPress}
|
||||||
activeOpacity={onPress ? 0.7 : 1}
|
activeOpacity={onPress ? 0.7 : 1}
|
||||||
>
|
>
|
||||||
<Text style={[styles.settingLabel, { color: textColor }]}>{label}</Text>
|
<Text style={[styles.settingLabel, { color: textColor }]}>{label}</Text>
|
||||||
<View style={styles.settingValueContainer}>
|
<View style={styles.settingValueContainer}>
|
||||||
<Text
|
<Text
|
||||||
style={[styles.settingValue, { color: subTextColor }]}
|
style={[styles.settingValue, { color: subTextColor }]}
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
|
|
||||||
const ActionButton = ({
|
const ActionButton = ({
|
||||||
title,
|
title,
|
||||||
onPress,
|
onPress,
|
||||||
destructive = false,
|
destructive = false,
|
||||||
}: {
|
}: {
|
||||||
title: string;
|
title: string;
|
||||||
onPress: () => void;
|
onPress: () => void;
|
||||||
destructive?: boolean;
|
destructive?: boolean;
|
||||||
}) => (
|
}) => (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[
|
style={[
|
||||||
styles.actionButton,
|
styles.actionButton,
|
||||||
{ backgroundColor: destructive ? destructiveColor : primary },
|
{ backgroundColor: destructive ? destructiveColor : primary },
|
||||||
]}
|
]}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
>
|
>
|
||||||
<Text style={styles.actionButtonText}>{title}</Text>
|
<Text style={styles.actionButtonText}>{title}</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView style={[styles.container, { backgroundColor: bgColor }]}>
|
<ScrollView style={[styles.container, { backgroundColor: bgColor }]}>
|
||||||
<View style={styles.content}>
|
<View style={styles.content}>
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
styles.section,
|
styles.section,
|
||||||
{
|
{
|
||||||
backgroundColor: sectionBg,
|
backgroundColor: sectionBg,
|
||||||
shadowColor: isDark ? "rgba(255,255,255,0.02)" : "#000",
|
shadowColor: isDark ? 'rgba(255,255,255,0.02)' : '#000',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
style={[
|
style={[
|
||||||
styles.sectionTitle,
|
styles.sectionTitle,
|
||||||
{ color: subTextColor, backgroundColor: sectionTitleBg },
|
{ color: subTextColor, backgroundColor: sectionTitleBg },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
User Information
|
Information
|
||||||
</Text>
|
</Text>
|
||||||
<SettingItem label="Username" value={user?.username || "Admin"} />
|
<SettingItem label="Username" value={user?.username || 'Admin'} />
|
||||||
<SettingItem label="Email" value={user?.email || "N/A"} />
|
<SettingItem label="Email" value={user?.email || 'N/A'} />
|
||||||
<SettingItem label="Server URL" value={serverAddress || "N/A"} />
|
<SettingItem label="Server URL" value={serverAddress || 'N/A'} />
|
||||||
</View>
|
<SettingItem label="App Version" value={`${Constants.expoConfig?.version}`} />
|
||||||
|
</View>
|
||||||
|
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
styles.section,
|
styles.section,
|
||||||
{
|
{
|
||||||
backgroundColor: sectionBg,
|
backgroundColor: sectionBg,
|
||||||
shadowColor: isDark ? "rgba(255,255,255,0.02)" : "#000",
|
shadowColor: isDark ? 'rgba(255,255,255,0.02)' : '#000',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
style={[
|
style={[
|
||||||
styles.sectionTitle,
|
styles.sectionTitle,
|
||||||
{ color: subTextColor, backgroundColor: sectionTitleBg },
|
{ color: subTextColor, backgroundColor: sectionTitleBg },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
App Info
|
Actions
|
||||||
</Text>
|
</Text>
|
||||||
<SettingItem label="Version" value="1.0.0" />
|
<ActionButton title="Logout" onPress={handleLogout} destructive />
|
||||||
<SettingItem label="Build" value="Expo" />
|
</View>
|
||||||
</View>
|
|
||||||
|
|
||||||
<View
|
<View style={styles.footer}>
|
||||||
style={[
|
<Text style={[styles.footerText, { color: subTextColor }]}>
|
||||||
styles.section,
|
UpSnap Mobile App
|
||||||
{
|
</Text>
|
||||||
backgroundColor: sectionBg,
|
<Text style={[styles.footerText, { color: subTextColor }]}>
|
||||||
shadowColor: isDark ? "rgba(255,255,255,0.02)" : "#000",
|
Connect to your UpSnap server
|
||||||
},
|
</Text>
|
||||||
]}
|
</View>
|
||||||
>
|
</View>
|
||||||
<Text
|
</ScrollView>
|
||||||
style={[
|
);
|
||||||
styles.sectionTitle,
|
|
||||||
{ color: subTextColor, backgroundColor: sectionTitleBg },
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
Actions
|
|
||||||
</Text>
|
|
||||||
<ActionButton title="Logout" onPress={handleLogout} destructive />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<View style={styles.footer}>
|
|
||||||
<Text style={[styles.footerText, { color: subTextColor }]}>
|
|
||||||
UpSnap Mobile App
|
|
||||||
</Text>
|
|
||||||
<Text style={[styles.footerText, { color: subTextColor }]}>
|
|
||||||
Connect to your UpSnap server
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: "#f5f5f5",
|
backgroundColor: '#f5f5f5',
|
||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
padding: 20,
|
padding: 20,
|
||||||
},
|
},
|
||||||
section: {
|
section: {
|
||||||
backgroundColor: "#fff",
|
backgroundColor: '#fff',
|
||||||
borderRadius: 12,
|
borderRadius: 12,
|
||||||
marginBottom: 20,
|
marginBottom: 20,
|
||||||
overflow: "hidden",
|
overflow: 'hidden',
|
||||||
shadowColor: "#000",
|
shadowColor: '#000',
|
||||||
shadowOffset: { width: 0, height: 2 },
|
shadowOffset: { width: 0, height: 2 },
|
||||||
shadowOpacity: 0.1,
|
shadowOpacity: 0.1,
|
||||||
shadowRadius: 4,
|
shadowRadius: 4,
|
||||||
elevation: 3,
|
elevation: 3,
|
||||||
},
|
},
|
||||||
sectionTitle: {
|
sectionTitle: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: "bold",
|
fontWeight: 'bold',
|
||||||
color: "#666",
|
color: '#666',
|
||||||
paddingHorizontal: 15,
|
paddingHorizontal: 15,
|
||||||
paddingTop: 15,
|
paddingTop: 15,
|
||||||
paddingBottom: 10,
|
paddingBottom: 10,
|
||||||
backgroundColor: "#f9f9f9",
|
backgroundColor: '#f9f9f9',
|
||||||
borderTopLeftRadius: 12,
|
borderTopLeftRadius: 12,
|
||||||
borderTopRightRadius: 12,
|
borderTopRightRadius: 12,
|
||||||
},
|
},
|
||||||
settingItem: {
|
settingItem: {
|
||||||
flexDirection: "row",
|
flexDirection: 'row',
|
||||||
justifyContent: "space-between",
|
justifyContent: 'space-between',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
paddingHorizontal: 15,
|
paddingHorizontal: 15,
|
||||||
paddingVertical: 15,
|
paddingVertical: 15,
|
||||||
borderBottomWidth: 1,
|
borderBottomWidth: 1,
|
||||||
borderBottomColor: "#f0f0f0",
|
borderBottomColor: '#f0f0f0',
|
||||||
},
|
},
|
||||||
settingLabel: {
|
settingLabel: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: "#333",
|
color: '#333',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
settingValueContainer: {
|
settingValueContainer: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
alignItems: "flex-end",
|
alignItems: 'flex-end',
|
||||||
},
|
},
|
||||||
settingValue: {
|
settingValue: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: "#666",
|
color: '#666',
|
||||||
maxWidth: 200,
|
maxWidth: 200,
|
||||||
},
|
},
|
||||||
actionButton: {
|
actionButton: {
|
||||||
backgroundColor: "#007AFF",
|
backgroundColor: '#007AFF',
|
||||||
margin: 15,
|
margin: 15,
|
||||||
padding: 15,
|
padding: 15,
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
actionButtonDestructive: {
|
actionButtonDestructive: {
|
||||||
backgroundColor: "#f44336",
|
backgroundColor: '#f44336',
|
||||||
},
|
},
|
||||||
actionButtonText: {
|
actionButtonText: {
|
||||||
color: "#fff",
|
color: '#fff',
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: "bold",
|
fontWeight: 'bold',
|
||||||
},
|
},
|
||||||
actionButtonTextDestructive: {
|
actionButtonTextDestructive: {
|
||||||
color: "#fff",
|
color: '#fff',
|
||||||
},
|
},
|
||||||
footer: {
|
footer: {
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
paddingVertical: 30,
|
paddingVertical: 30,
|
||||||
},
|
},
|
||||||
footerText: {
|
footerText: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: "#999",
|
color: '#999',
|
||||||
marginBottom: 5,
|
marginBottom: 5,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export default function LoginScreen() {
|
|||||||
>
|
>
|
||||||
<ScrollView contentContainerStyle={styles.scrollContent}>
|
<ScrollView contentContainerStyle={styles.scrollContent}>
|
||||||
<View style={styles.header}>
|
<View style={styles.header}>
|
||||||
<Text style={[styles.title, { color: textColor }]}>Remote WoL</Text>
|
<Text style={[styles.title, { color: textColor }]}>Jumpstart</Text>
|
||||||
<Text style={[styles.subtitle, { color: subText }]}>
|
<Text style={[styles.subtitle, { color: subText }]}>
|
||||||
Mobile Frontend for UpSnap
|
Mobile Frontend for UpSnap
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
BIN
assets/remotewol-ios.icon/Assets/Image.png
Normal file
BIN
assets/remotewol-ios.icon/Assets/Image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/remotewol-ios.icon/Assets/display 2.png
Normal file
BIN
assets/remotewol-ios.icon/Assets/display 2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
assets/remotewol-ios.icon/Assets/display 3.png
Normal file
BIN
assets/remotewol-ios.icon/Assets/display 3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/remotewol-ios.icon/Assets/display.png
Normal file
BIN
assets/remotewol-ios.icon/Assets/display.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 54 KiB |
@@ -1,19 +1,48 @@
|
|||||||
{
|
{
|
||||||
"fill" : {
|
"fill" : {
|
||||||
"automatic-gradient" : "extended-srgb:0.00000,0.53333,1.00000,1.00000"
|
"automatic-gradient" : "extended-gray:1.00000,1.00000"
|
||||||
},
|
},
|
||||||
"groups" : [
|
"groups" : [
|
||||||
{
|
{
|
||||||
"layers" : [
|
"layers" : [
|
||||||
{
|
{
|
||||||
"glass" : true,
|
"hidden" : false,
|
||||||
"image-name" : "gopher.svg",
|
"image-name" : "Image.png",
|
||||||
"name" : "gopher",
|
"name" : "Image",
|
||||||
"position" : {
|
"position" : {
|
||||||
"scale" : 0.45,
|
"scale" : 0.65,
|
||||||
"translation-in-points" : [
|
"translation-in-points" : [
|
||||||
-6.017952794793246,
|
0,
|
||||||
-0.4600234584925147
|
-52.942187500000045
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"fill-specializations" : [
|
||||||
|
{
|
||||||
|
"appearance" : "dark",
|
||||||
|
"value" : "none"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"image-name-specializations" : [
|
||||||
|
{
|
||||||
|
"value" : "display 2.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearance" : "dark",
|
||||||
|
"value" : "display.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearance" : "tinted",
|
||||||
|
"value" : "display 3.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name" : "display 3",
|
||||||
|
"position" : {
|
||||||
|
"scale" : 1.25,
|
||||||
|
"translation-in-points" : [
|
||||||
|
0,
|
||||||
|
-10.625
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user