2025-07-05 17:12:20 +02:00
|
|
|
import { useRouter } from "expo-router";
|
2025-07-05 14:05:54 +02:00
|
|
|
import { useCallback, useState } from "react";
|
|
|
|
import {
|
2025-07-05 15:25:51 +02:00
|
|
|
ImageBackground,
|
|
|
|
KeyboardAvoidingView,
|
|
|
|
Platform,
|
|
|
|
ScrollView,
|
|
|
|
Text,
|
|
|
|
TextInput,
|
|
|
|
TouchableOpacity,
|
|
|
|
View,
|
2025-07-05 14:05:54 +02:00
|
|
|
} from "react-native";
|
|
|
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
|
|
import { styles } from "./styles";
|
|
|
|
|
2025-07-05 17:12:20 +02:00
|
|
|
const converterBgImage = require("../assets/images/nether.png");
|
2025-07-05 14:05:54 +02:00
|
|
|
|
|
|
|
export default function CoordinateConverter() {
|
2025-07-05 15:25:51 +02:00
|
|
|
const router = useRouter();
|
|
|
|
|
2025-07-05 14:05:54 +02:00
|
|
|
const [overworldX, setOverworldX] = useState("");
|
|
|
|
const [overworldZ, setOverworldZ] = useState("");
|
|
|
|
const [netherX, setNetherX] = useState("");
|
|
|
|
const [netherZ, setNetherZ] = useState("");
|
|
|
|
|
|
|
|
const safeParseFloat = (value: string) => {
|
|
|
|
const num = parseFloat(value);
|
|
|
|
return isNaN(num) ? undefined : num;
|
|
|
|
};
|
|
|
|
|
|
|
|
const convertOWToNether = useCallback(
|
|
|
|
(xStr: string, zStr: string) => {
|
|
|
|
const x = safeParseFloat(xStr);
|
|
|
|
const z = safeParseFloat(zStr);
|
|
|
|
if (x !== undefined && z !== undefined) {
|
|
|
|
setNetherX(Math.floor(x / 8).toString());
|
|
|
|
setNetherZ(Math.floor(z / 8).toString());
|
|
|
|
} else {
|
|
|
|
setNetherX("");
|
|
|
|
setNetherZ("");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[]
|
|
|
|
);
|
|
|
|
|
|
|
|
const convertNetherToOW = useCallback(
|
|
|
|
(xStr: string, zStr: string) => {
|
|
|
|
const x = safeParseFloat(xStr);
|
|
|
|
const z = safeParseFloat(zStr);
|
|
|
|
if (x !== undefined && z !== undefined) {
|
|
|
|
setOverworldX(Math.floor(x * 8).toString());
|
|
|
|
setOverworldZ(Math.floor(z * 8).toString());
|
|
|
|
} else {
|
|
|
|
setOverworldX("");
|
|
|
|
setOverworldZ("");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[]
|
|
|
|
);
|
|
|
|
|
|
|
|
const handleOverworldXChange = useCallback(
|
|
|
|
(text: string) => {
|
|
|
|
setOverworldX(text);
|
|
|
|
convertOWToNether(text, overworldZ);
|
|
|
|
},
|
|
|
|
[overworldZ, convertOWToNether]
|
|
|
|
);
|
|
|
|
|
|
|
|
const handleOverworldZChange = useCallback(
|
|
|
|
(text: string) => {
|
|
|
|
setOverworldZ(text);
|
|
|
|
convertOWToNether(overworldX, text);
|
|
|
|
},
|
|
|
|
[overworldX, convertOWToNether]
|
|
|
|
);
|
|
|
|
|
|
|
|
const handleNetherXChange = useCallback(
|
|
|
|
(text: string) => {
|
|
|
|
setNetherX(text);
|
|
|
|
convertNetherToOW(text, netherZ);
|
|
|
|
},
|
|
|
|
[netherZ, convertNetherToOW]
|
|
|
|
);
|
|
|
|
|
|
|
|
const handleNetherZChange = useCallback(
|
|
|
|
(text: string) => {
|
|
|
|
setNetherZ(text);
|
|
|
|
convertNetherToOW(netherX, text);
|
|
|
|
},
|
|
|
|
[netherX, convertNetherToOW]
|
|
|
|
);
|
|
|
|
|
|
|
|
const handleClear = useCallback(() => {
|
|
|
|
setOverworldX("");
|
|
|
|
setOverworldZ("");
|
|
|
|
setNetherX("");
|
|
|
|
setNetherZ("");
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
return (
|
2025-07-05 15:25:51 +02:00
|
|
|
<View style={styles.converterScreenRoot}>
|
2025-07-05 14:05:54 +02:00
|
|
|
<ImageBackground
|
|
|
|
source={converterBgImage}
|
|
|
|
style={styles.converterBackgroundImage}
|
|
|
|
resizeMode="cover"
|
|
|
|
>
|
2025-07-05 15:25:51 +02:00
|
|
|
<View style={styles.converterBackgroundOverlay} />
|
|
|
|
</ImageBackground>
|
|
|
|
|
|
|
|
<SafeAreaView style={styles.converterContentWrapper}>
|
|
|
|
<KeyboardAvoidingView
|
|
|
|
style={styles.converterContainer}
|
|
|
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
|
|
>
|
|
|
|
<ScrollView contentContainerStyle={styles.converterScrollContent}>
|
|
|
|
{/* Custom Back Button */}
|
|
|
|
<TouchableOpacity
|
|
|
|
onPress={() => router.back()}
|
|
|
|
style={styles.backButton}
|
|
|
|
>
|
|
|
|
<Text style={styles.backButtonText}>← Go Back</Text>
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
2025-07-05 15:28:47 +02:00
|
|
|
<Text style={styles.converterTitle}>Nether Portal Calculator</Text>
|
2025-07-05 15:25:51 +02:00
|
|
|
|
|
|
|
{/* Overworld Row */}
|
|
|
|
<View style={styles.dimensionContainer}>
|
|
|
|
<Text style={styles.dimensionTitle}>Overworld</Text>
|
|
|
|
<View style={styles.coordinatesRow}>
|
|
|
|
<View style={styles.coordInputGroup}>
|
|
|
|
<Text style={styles.coordInputLabel}>X:</Text>
|
|
|
|
<TextInput
|
|
|
|
style={styles.coordTextInput}
|
|
|
|
keyboardType="numeric"
|
|
|
|
placeholder="0"
|
|
|
|
placeholderTextColor="#ccc"
|
|
|
|
value={overworldX}
|
|
|
|
onChangeText={handleOverworldXChange}
|
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
<View style={styles.coordInputGroup}>
|
|
|
|
<Text style={styles.coordInputLabel}>Z:</Text>
|
|
|
|
<TextInput
|
|
|
|
style={styles.coordTextInput}
|
|
|
|
keyboardType="numeric"
|
|
|
|
placeholder="0"
|
|
|
|
placeholderTextColor="#ccc"
|
|
|
|
value={overworldZ}
|
|
|
|
onChangeText={handleOverworldZChange}
|
|
|
|
/>
|
2025-07-05 14:05:54 +02:00
|
|
|
</View>
|
|
|
|
</View>
|
2025-07-05 15:25:51 +02:00
|
|
|
</View>
|
2025-07-05 14:05:54 +02:00
|
|
|
|
2025-07-05 15:25:51 +02:00
|
|
|
{/* Nether Row */}
|
|
|
|
<View style={styles.dimensionContainer}>
|
|
|
|
<Text style={styles.dimensionTitle}>Nether</Text>
|
|
|
|
<View style={styles.coordinatesRow}>
|
|
|
|
<View style={styles.coordInputGroup}>
|
|
|
|
<Text style={styles.coordInputLabel}>X:</Text>
|
|
|
|
<TextInput
|
|
|
|
style={styles.coordTextInput}
|
|
|
|
keyboardType="numeric"
|
|
|
|
placeholder="0"
|
|
|
|
placeholderTextColor="#ccc"
|
|
|
|
value={netherX}
|
|
|
|
onChangeText={handleNetherXChange}
|
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
<View style={styles.coordInputGroup}>
|
|
|
|
<Text style={styles.coordInputLabel}>Z:</Text>
|
|
|
|
<TextInput
|
|
|
|
style={styles.coordTextInput}
|
|
|
|
keyboardType="numeric"
|
|
|
|
placeholder="0"
|
|
|
|
placeholderTextColor="#ccc"
|
|
|
|
value={netherZ}
|
|
|
|
onChangeText={handleNetherZChange}
|
|
|
|
/>
|
2025-07-05 14:05:54 +02:00
|
|
|
</View>
|
|
|
|
</View>
|
2025-07-05 15:25:51 +02:00
|
|
|
</View>
|
2025-07-05 14:05:54 +02:00
|
|
|
|
2025-07-05 15:25:51 +02:00
|
|
|
<TouchableOpacity style={styles.clearButton} onPress={handleClear}>
|
|
|
|
<Text style={styles.clearButtonText}>Clear All</Text>
|
|
|
|
</TouchableOpacity>
|
|
|
|
</ScrollView>
|
|
|
|
</KeyboardAvoidingView>
|
|
|
|
</SafeAreaView>
|
|
|
|
</View>
|
2025-07-05 14:05:54 +02:00
|
|
|
);
|
|
|
|
}
|