add screens

This commit is contained in:
Jordan Hewitt 2025-02-01 07:37:41 -08:00
parent 7f60c25393
commit 5c5cf48f6e
6 changed files with 227 additions and 0 deletions

57
app/(screens)/_layout.tsx Normal file
View File

@ -0,0 +1,57 @@
import React, { useEffect } from 'react';
import { View, StyleSheet, TouchableOpacity } from 'react-native';
import { useFonts } from 'expo-font';
import * as SplashScreen from 'expo-splash-screen';
import { ThemeProvider, DarkTheme, DefaultTheme, NavigationContainer } from '@react-navigation/native';
import Settings from '@/components/Settings';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import HomeScreen from '.';
import { LanguageSelection } from '@/components/LanguageSelection';
import { language_matrix_entry } from '../i18n/api';
import ConversationThread from '@/components/ConversationThread';
const Stack = createNativeStackNavigator();
export default function _layout() {
const [loaded] = useFonts({
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
});
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
}
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{title: 'Welcome'}}
/>
<Stack.Screen
name="LanguageSelection"
component={LanguageSelection}
/>
<Stack.Screen
name="Conversation"
component={ConversationThread}
/>
<Stack.Screen name="Settings" component={Settings} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
settingsIconContainer: {
marginLeft: 16,
},
});

45
app/(screens)/index.tsx Normal file
View File

@ -0,0 +1,45 @@
import { LanguageSelection } from '@/components/LanguageSelection';
import { useState } from 'react';
import { Button, Text, View } from 'react-native';
import { Image, StyleSheet, Platform } from 'react-native';
import { Conversation, Speaker } from '../lib/conversation';
import { language_matrix_entry, Translator } from '../i18n/api';
import ConversationThread from '@/components/ConversationThread';
import { NavigationContainerProps, NavigationProp, ParamListBase } from '@react-navigation/native';
export default function HomeScreen({navigation} : {navigation: NavigationProp<ParamListBase>}) {
const [language, setLanguage] = useState<language_matrix_entry | undefined>()
const [conversation, setConversation] = useState<Conversation | undefined>();
return (
conversation ? <ConversationThread conversation={conversation} /> :
<View>
<Button
title="Settings"
onPress={() =>
navigation.navigate('Settings')
}
/>
</View>
);
}
const styles = StyleSheet.create({
titleContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
stepContainer: {
gap: 8,
marginBottom: 8,
},
reactLogo: {
height: 178,
width: 290,
bottom: 0,
left: 0,
position: 'absolute',
},
});

View File

View File

@ -0,0 +1,73 @@
import {describe, expect, beforeEach} from '@jest/globals';
import {Settings} from '@/app/lib/settings';
import { getDb } from '@/app/lib/db';
describe('Settings', () => {
let settings: Settings;
beforeEach(async () => {
// Initialize your Settings class here with a fresh database instance
settings = new Settings(await getDb());
});
afterEach(async () => {
// Clean up the database after each test
await settings.db.executeSql('DELETE FROM settings');
});
describe('setHostLanguage', () => {
it('should set the host language in the database', async () => {
const value = 'en';
await settings.setHostLanguage(value);
const result = await settings.getHostLanguage();
expect(result).toEqual(value);
});
});
describe('getHostLanguage', () => {
it('should return the host language from the database', async () => {
const value = 'fr';
await settings.db.executeSql(
`INSERT INTO settings (host_language) VALUES (?)`,
[value]
);
const result = await settings.getHostLanguage();
expect(result).toEqual(value);
});
it('should return null if the host language is not set', async () => {
const result = await settings.getHostLanguage();
expect(result).not.toBeNull();
});
});
describe('setLibretranslateBaseUrl', () => {
it('should set the LibreTranslate base URL in the database', async () => {
const value = 'https://example.com';
await settings.setLibetransalteBaseUrl(value);
const result = await settings.getLibretranslateBaseUrl();
expect(result).toEqual(value);
});
});
describe('getLibretranslateBaseUrl', () => {
it('should return the LibreTranslate base URL from the database', async () => {
const value = 'https://another-example.com';
await settings.db.executeSql(
`INSERT INTO settings (libetransalte_base_url) VALUES (?)`,
[value]
);
const result = await settings.getLibretranslateBaseUrl();
expect(result).toEqual(value);
});
it('should return null if the LibreTranslate base URL is not set', async () => {
const result = await settings.getLibretranslateBaseUrl();
expect(result).not.toBeNull();
});
});
});

46
app/lib/settings.ts Normal file
View File

@ -0,0 +1,46 @@
import { SQLiteDatabase } from "react-native-sqlite-storage";
export class Settings {
constructor(public db: SQLiteDatabase) {
}
private async getValue(key: string) {
const query = `
SELECT ${key}
FROM settings
LIMIT 1`
const result = await this.db.executeSql(
query
);
result[0].rows.item(0).host_language;
}
private async setValue(key: string, value: any) {
const statement = `INSERT INTO settings (${key})
SELECT '?'
ON CONFLICT DO UPDATE SET ${key} = ?`
await this.db.transaction(async (tx) => {
await tx.executeSql(statement, [value, value]);
})
}
async setHostLanguage(value: string) {
await this.setValue("host_language", value);
}
async getHostLanguage() {
return await this.getValue("host_language")
}
async setLibetransalteBaseUrl(value : string) {
await this.setValue("libetransalte_base_url", value)
}
async getLibretranslateBaseUrl() {
await this.getValue("libtretranslate_base_url")
}
}

6
babel.config.js Normal file
View File

@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript',
],
};