fix component. Add flags.

This commit is contained in:
Jordan
2025-01-24 06:25:37 -08:00
parent 8cc1048251
commit 0c9daf8e4a
17 changed files with 334 additions and 33 deletions

18
components/HapticTab.tsx Normal file
View File

@ -0,0 +1,18 @@
import { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs';
import { PlatformPressable } from '@react-navigation/elements';
import * as Haptics from 'expo-haptics';
export function HapticTab(props: BottomTabBarButtonProps) {
return (
<PlatformPressable
{...props}
onPressIn={(ev) => {
if (process.env.EXPO_OS === 'ios') {
// Add a soft haptic feedback when pressing down on the tabs.
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}
props.onPressIn?.(ev);
}}
/>
);
}

View File

@ -0,0 +1,50 @@
import { CachedTranslator, Translator, language_matrix } from "@/app/i18n/api";
import { LIBRETRANSLATE_BASE_URL } from "@/constants/api";
import { Text } from "@react-navigation/elements";
import { useEffect, useState } from "react";
import ISpeakButton from "./ui/ISpeakButton";
import { LANG_FLAGS } from "@/app/i18n/lang";
import { ScrollView } from "react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
export function LanguageSelection(props : {
translator? : Translator
}) {
const [languages, setLanguages] = useState<language_matrix|undefined>();
const [languagesLoaded, setLanguagesLoaded] = useState<boolean>(false);
const translator = props.translator || new CachedTranslator("en")
useEffect(() => {
const fetchData = async () => {
try {
// Replace with your actual async data fetching logic
const languages = await translator.fetchLanguages();
setLanguages(languages);
setLanguagesLoaded(true);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
}, []);
return (
<ScrollView >
<SafeAreaProvider >
<SafeAreaView>
{(languages && languagesLoaded) ? Object.entries(languages).filter((l) => (LANG_FLAGS as any)[l[0]] !== undefined).map(
([lang, lang_entry]) => {
return (
<ISpeakButton language={lang_entry} key={lang_entry.code} />
);
}
) : <Text>Waiting...</Text>
}
</SafeAreaView>
</SafeAreaProvider>
</ScrollView>
)
}

View File

@ -1,37 +1,108 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import { CachedTranslator } from "@/app/i18n/api"
import { CachedTranslator, Translator, language_matrix_entry } from "@/app/i18n/api"
import { longLang } from "@/app/i18n/lang"
import { useEffect, useRef, useState } from "react"
import { Button } from "react-native"
import React, { useEffect, useRef, useState } from "react"
import { Button, Image, ImageBackground, Pressable, StyleSheet, TouchableOpacity, View } from "react-native"
import { Text } from '@react-navigation/elements';
import CountryFlag from "react-native-country-flag";
import { chooseCountry } from '@/app/i18n/countries';
type ISpeakButtonProps = {
country: string,
language: string,
language: language_matrix_entry,
translator?: Translator,
}
function iSpeak(language : string) {
return `I speak ${longLang(language)}.`
function iSpeak(language : language_matrix_entry) {
return `I speak ${language.name}.`
}
async function iSpeakTr(targetLang : string, sourceLang = "en") {
async function iSpeakTr(translator : CachedTranslator, targetLang : language_matrix_entry) {
const sourceStr = iSpeak(targetLang)
const translator = new CachedTranslator(sourceLang, targetLang);
return await translator.translate(sourceStr)
return await translator.translate(sourceStr, targetLang.code);
}
const DEFAULT_FLAGS = {
"en": ["us", "gb"],
// "sq": ["al"],
"ar": ["ae"],
"es": ["es"],
"pt": ["pt"],
"ru": ["ru"],
"it": ["it"],
"ir": ["ie"],
"sk": ["sk"],
"ro": ["ro"],
"ja": ["jp"],
"ko": ["kp", "kr"],
"el": ["gr"],
"fr": ["fr"],
"de": ["de"],
"nl": ["nl"],
"cz": ["cz"],
"uk": ["ua"],
"he": ["il"],
"hi": ["in"],
"gl": ["es"],
"fa": ["ir"],
"ur": ["pk"],
"ga": ["ie"],
"eo": ["es"]
}
const ISpeakButton = (props : ISpeakButtonProps) => {
const [title, setTitle] = useState("");
const [title, setTitle] = useState<string | undefined>();
const [titleLoaded, setTitleLoaded] = useState<boolean>(false);
const translator = props.translator || new CachedTranslator("en");
useEffect(() => {
async function () {
setTitle(await iSpeakTr(props.language) as string);
}
}, []);
const fetchData = async () => {
try {
// Replace with your actual async data fetching logic
const title = await iSpeakTr(translator, props.language);
setTitle(title);
} catch (error) {
console.error('Error fetching data:', error);
} finally {
setTitleLoaded(true);
}
};
fetchData();
}, []);
const countries = DEFAULT_FLAGS[props.language.code] || chooseCountry(props.language.code);
return (
title ? (
<TouchableOpacity style={styles.button}>
<View>
{countries &&
countries.map( c => {
return <CountryFlag isoCode={c} size={25} key={c}/> }
)
}
<Text style={{textAlign: "center", verticalAlign: "bottom"}}>{ title } { props.language.name } { props.language.code }</Text>
</View>
</TouchableOpacity>
) : (
<Text>Loading...</Text>
)
)
<Button onPress={setLanguage} title={}>
</Button>
}
const styles = StyleSheet.create({
button: {
// backgroundColor: "blue",
width: "20%",
// height: "20%",
margin: 5,
borderRadius: 10,
borderColor: "white",
borderWidth: 1,
borderStyle: "solid",
}
})
export default ISpeakButton;

View File

@ -0,0 +1,43 @@
// This file is a fallback for using MaterialIcons on Android and web.
import MaterialIcons from '@expo/vector-icons/MaterialIcons';
import { SymbolWeight } from 'expo-symbols';
import React from 'react';
import { OpaqueColorValue, StyleProp, ViewStyle } from 'react-native';
// Add your SFSymbol to MaterialIcons mappings here.
const MAPPING = {
// See MaterialIcons here: https://icons.expo.fyi
// See SF Symbols in the SF Symbols app on Mac.
'house.fill': 'home',
'paperplane.fill': 'send',
'chevron.left.forwardslash.chevron.right': 'code',
'chevron.right': 'chevron-right',
} as Partial<
Record<
import('expo-symbols').SymbolViewProps['name'],
React.ComponentProps<typeof MaterialIcons>['name']
>
>;
export type IconSymbolName = keyof typeof MAPPING;
/**
* An icon component that uses native SFSymbols on iOS, and MaterialIcons on Android and web. This ensures a consistent look across platforms, and optimal resource usage.
*
* Icon `name`s are based on SFSymbols and require manual mapping to MaterialIcons.
*/
export function IconSymbol({
name,
size = 24,
color,
style,
}: {
name: IconSymbolName;
size?: number;
color: string | OpaqueColorValue;
style?: StyleProp<ViewStyle>;
weight?: SymbolWeight;
}) {
return <MaterialIcons color={color} size={size} name={MAPPING[name]} style={style} />;
}

View File

@ -0,0 +1,6 @@
// This is a shim for web and Android where the tab bar is generally opaque.
export default undefined;
export function useBottomTabOverflow() {
return 0;
}