work on navigation component workflow.

This commit is contained in:
Jordan Hewitt
2025-02-22 18:28:10 -08:00
parent 6673663883
commit eb7599bfe8
8 changed files with 116 additions and 32 deletions

View File

@ -67,6 +67,7 @@ const ConversationThread = ({ route } : {route?: Route<"Conversation", {conversa
return cachedTranslator ? (
<View style={{ flex: 1, flexDirection: "column" }}>
<Text>Conversation Thread</Text>
<ScrollView
style={{
borderColor: "black",

View File

@ -1,4 +1,4 @@
import { CachedTranslator, Translator, language_matrix, language_matrix_entry } from "@/app/i18n/api";
import { CachedTranslator, LanguageServer, Translator, language_matrix, language_matrix_entry } from "@/app/i18n/api";
import { LIBRETRANSLATE_BASE_URL } from "@/constants/api";
import { useEffect, useState } from "react";
import ISpeakButton from "./ui/ISpeakButton";
@ -7,17 +7,19 @@ import { ScrollView, StyleSheet, Text, View } from "react-native";
import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
import { Conversation, Speaker } from "@/app/lib/conversation";
import { NavigationProp, ParamListBase } from "@react-navigation/native";
import { Link } from "expo-router";
export function LanguageSelection(props: {
navigation?: NavigationProp<ParamListBase>
translator?: Translator
onLangSelected? : (lang : language_matrix_entry) => any
onLangSelected?: (lang: language_matrix_entry) => any
}) {
const [languages, setLanguages] = useState<language_matrix | undefined>();
const [languagesLoaded, setLanguagesLoaded] = useState<boolean>(false);
const translator = props.translator || new CachedTranslator("en")
const languageServer = new LanguageServer(LIBRETRANSLATE_BASE_URL);
const translator = props.translator || new CachedTranslator("en", undefined, languageServer);
function onLangSelected(language: language_matrix_entry) {
props.onLangSelected && props.onLangSelected(language)
@ -28,7 +30,7 @@ export function LanguageSelection(props: {
const fetchData = async () => {
try {
// Replace with your actual async data fetching logic
const languages = await translator.fetchLanguages();
const languages = await languageServer.fetchLanguages();
setLanguages(languages);
setLanguagesLoaded(true);
} catch (error) {
@ -41,20 +43,25 @@ export function LanguageSelection(props: {
}, []);
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} onLangSelected={onLangSelected} />
);
<View>
<Link href={"/settings"}>
<Text>Settings</Text>
</Link>
<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} onLangSelected={onLangSelected} />
);
}
) : <Text>Waiting...</Text>
}
) : <Text>Waiting...</Text>
}
</SafeAreaView>
</SafeAreaProvider>
</ScrollView>
</SafeAreaView>
</SafeAreaProvider>
</ScrollView>
</View>
)
}

View File

@ -2,16 +2,38 @@ import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import SettingsComponent from '@/components/Settings';
import { LanguageSelection } from '@/components/LanguageSelection';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createNativeStackNavigator, NativeStackNavigationProp } from '@react-navigation/native-stack';
import {
useNavigation,
} from '@react-navigation/native'
import ConversationThread from '@/components/ConversationThread';
import { language_matrix_entry, Translator } from '@/app/i18n/api';
import { useRouter } from 'expo-router';
import { Conversation } from '@/app/lib/conversation';
import { Settings } from '@/app/lib/settings';
import { RootStackParamList } from '@/navigation.types';
const Stack = createNativeStackNavigator();
export default function TTNavStack() {
async function onLangSelected(lang: language_matrix_entry) {
const nav = useNavigation<NativeStackNavigationProp<RootStackParamList, 'ConversationThread'>>();
const settings = await Settings.getDefault();
const hostLanguage = await settings.getHostLanguage();
const conversation = new Conversation(
(await Translator.getDefault(lang.code)),
{ id: "host", language: hostLanguage },
{ "id": "guest", language: lang.code, }
)
nav.navigate("Conversation", { conversation, })
}
return (
<NavigationContainer>
<Stack.Navigator initialRouteName='LanguageSelection'>
<Stack.Screen name="LanguageSelection" component={LanguageSelection} />
<Stack.Screen name="LanguageSelection" component={({ ...props }) => <LanguageSelection {...props} onLangSelected={onLangSelected} />} />
<Stack.Screen name="ConversationThread" component={ConversationThread} />
<Stack.Screen name="Settings" component={SettingsComponent} />
</Stack.Navigator>

View File

@ -1,17 +1,11 @@
import {dirname, resolve} from 'path'
import React from 'react';
import { fireEvent, render, screen } from '@testing-library/react-native';
import { NavigationContainer } from '@react-navigation/native';
import { act, fireEvent, render, screen } from '@testing-library/react-native';
import { createStackNavigator } from '@react-navigation/stack';
import TTNavStack from '../TTNavStack';
// Mock the expo-file-system/next module
jest.mock('expo-file-system/next', () => ({
File: jest.fn(),
Paths: {
join: jest.fn(),
},
}));
jest.mock("@/app/i18n/api", () => require("../../__mocks__/api.ts"));
import TTNavStack from '../TTNavStack';
const Stack = createStackNavigator();
@ -23,15 +17,19 @@ describe('Navigation', () => {
it('Navigates to ConversationThread on language selection', async () => {
render(<TTNavStack />);
const languageSelectionText = await screen.findByText("Language Selection");
fireEvent.press(languageSelectionText);
const languageSelectionText = await screen.findByText(/I Speak French\./i);
act(() => {
fireEvent.press(languageSelectionText);
})
expect(await screen.findByText("Conversation Thread")).toBeOnTheScreen();
});
it('Navigates to Settings on settings selection', async () => {
render(<TTNavStack />);
const settingsButton = await screen.findByText("Settings");
fireEvent.press(settingsButton);
act(() => {
fireEvent.press(settingsButton)
})
expect(await screen.findByText("Settings")).toBeOnTheScreen();
});
});