work on downloading some more.
This commit is contained in:
@ -8,6 +8,7 @@ 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, useNavigation } from "expo-router";
|
||||
import { migrateDb } from "@/app/lib/db";
|
||||
|
||||
|
||||
export function LanguageSelection(props: {
|
||||
@ -30,6 +31,7 @@ export function LanguageSelection(props: {
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
await migrateDb();
|
||||
try {
|
||||
// Replace with your actual async data fetching logic
|
||||
setTranslator(await CachedTranslator.getDefault());
|
||||
@ -49,12 +51,12 @@ export function LanguageSelection(props: {
|
||||
<Text>Settings</Text>
|
||||
</Pressable>
|
||||
<ScrollView >
|
||||
<SafeAreaProvider >
|
||||
<SafeAreaView>
|
||||
<SafeAreaProvider>
|
||||
<SafeAreaView style={styles.table}>
|
||||
{(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} translator={translator} />
|
||||
<ISpeakButton language={lang_entry} key={lang_entry.code} onLangSelected={onLangSelected} translator={translator} />
|
||||
);
|
||||
}
|
||||
) : <Text>Waiting...</Text>
|
||||
@ -66,11 +68,15 @@ export function LanguageSelection(props: {
|
||||
)
|
||||
}
|
||||
|
||||
const DEBUG_BORDER = {
|
||||
borderWidth: 3,
|
||||
borderStyle: "dotted",
|
||||
borderColor: "blue",
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
column: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
padding: 8,
|
||||
table: {
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
})
|
@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { View, Text, TextInput, Pressable, StyleSheet } from "react-native";
|
||||
import {
|
||||
WHISPER_FILES,
|
||||
WhisperFile,
|
||||
download_status_t,
|
||||
whisper_tag_t,
|
||||
@ -34,33 +35,36 @@ const SettingsComponent = () => {
|
||||
} | null>(null);
|
||||
const [whisperModel, setWhisperModel] =
|
||||
useState<keyof typeof WHISPER_MODELS>("small");
|
||||
const [downloader, setDownloader] = useState<any>(null);
|
||||
const [whisperFile, setWhisperFile] = useState<WhisperFile | undefined>();
|
||||
const [downloadStatus, setDownloadStatus] = useState<
|
||||
undefined | download_status_t
|
||||
>();
|
||||
const [whisperFileExists, setWhisperFileExists] = useState<boolean>(false);
|
||||
const [isWhisperHashValid, setIsWhisperHashValid] = useState<boolean>(false);
|
||||
const [downloader, setDownloader] = useState<any>(null);
|
||||
const [bytesDone, setBytesDone] = useState<number | undefined>();
|
||||
const [bytesRemaining, setBytesRemaining] = useState<number | undefined>();
|
||||
const [statusTimeout, setStatusTimeout] = useState<
|
||||
NodeJS.Timeout | undefined
|
||||
>();
|
||||
|
||||
useEffect(() => {
|
||||
loadSettings();
|
||||
}, []);
|
||||
(async function () {
|
||||
const settings = await Settings.getDefault();
|
||||
setHostLanguage((await settings.getHostLanguage()) || "en");
|
||||
setLibretranslateBaseUrl(
|
||||
(await settings.getLibretranslateBaseUrl()) || LIBRETRANSLATE_BASE_URL
|
||||
);
|
||||
setWhisperModel((await settings.getWhisperModel()) || "small");
|
||||
setWhisperFile(WHISPER_FILES[whisperModel]);
|
||||
await whisperFile?.syncHfMetadata();
|
||||
await whisperFile?.updateTargetExistence();
|
||||
await whisperFile?.updateTargetHash();
|
||||
})();
|
||||
}, [whisperFile]);
|
||||
|
||||
const getLanguageOptions = async () => {
|
||||
const languageServer = await LanguageServer.getDefault();
|
||||
setLanguageOptions(await languageServer.fetchLanguages());
|
||||
};
|
||||
|
||||
const loadSettings = async () => {
|
||||
const settings = await Settings.getDefault();
|
||||
setHostLanguage((await settings.getHostLanguage()) || "en");
|
||||
setLibretranslateBaseUrl(
|
||||
(await settings.getLibretranslateBaseUrl()) || LIBRETRANSLATE_BASE_URL
|
||||
);
|
||||
setWhisperModel(await settings.getWhisperModel());
|
||||
};
|
||||
|
||||
const handleHostLanguageChange = async (lang: string) => {
|
||||
const settings = await Settings.getDefault();
|
||||
setHostLanguage(lang);
|
||||
@ -83,17 +87,24 @@ const SettingsComponent = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const intervalUpdateDownloadStatus = async () => {
|
||||
if (!whisperFile) return;
|
||||
const status = await whisperFile.getDownloadStatus();
|
||||
setDownloadStatus(status);
|
||||
};
|
||||
|
||||
const handleWhisperModelChange = async (model: whisper_tag_t) => {
|
||||
const settings = await Settings.getDefault();
|
||||
await settings.setWhisperModel(model);
|
||||
setWhisperModel(model);
|
||||
setWhisperFile(new WhisperFile(model));
|
||||
const wFile = WHISPER_FILES[whisperModel];
|
||||
await wFile.syncHfMetadata();
|
||||
await wFile.updateTargetExistence();
|
||||
await wFile.updateTargetHash();
|
||||
setIsWhisperHashValid(wFile.isHashValid);
|
||||
setWhisperFile(wFile);
|
||||
setWhisperFileExists(wFile.does_target_exist);
|
||||
};
|
||||
|
||||
const doSetDownloadStatus = (arg0: WhisperFile) => {
|
||||
console.log("Downloading ....")
|
||||
setIsWhisperHashValid(arg0.isHashValid);
|
||||
setBytesDone(arg0.download_data?.totalBytesWritten);
|
||||
setBytesRemaining(arg0.download_data?.totalBytesExpectedToWrite);
|
||||
};
|
||||
|
||||
const doDownload = async () => {
|
||||
@ -101,16 +112,16 @@ const SettingsComponent = () => {
|
||||
throw new Error("Could not start download because whisperModel not set.");
|
||||
}
|
||||
|
||||
console.log("Starging download of %s", whisperModel)
|
||||
console.log("Starting download of %s", whisperModel);
|
||||
|
||||
const whisperFile = new WhisperFile(whisperModel);
|
||||
if (!whisperFile) throw new Error("No whisper file");
|
||||
|
||||
const resumable = await whisperFile.createDownloadResumable();
|
||||
setDownloader(resumable);
|
||||
try {
|
||||
await resumable.downloadAsync();
|
||||
const statusTimeout = setInterval(intervalUpdateDownloadStatus, 200);
|
||||
setStatusTimeout(statusTimeout);
|
||||
const resumable = await whisperFile.createDownloadResumable({
|
||||
onData: doSetDownloadStatus,
|
||||
});
|
||||
setDownloader(resumable);
|
||||
await resumable.resumeAsync();
|
||||
} catch (error) {
|
||||
console.error("Failed to download whisper model:", error);
|
||||
}
|
||||
@ -174,28 +185,22 @@ const SettingsComponent = () => {
|
||||
))}
|
||||
</Picker>
|
||||
<View>
|
||||
{whisperModel &&
|
||||
(downloadStatus?.isDownloadComplete ? (
|
||||
downloadStatus?.doesTargetExist ? (
|
||||
<Pressable onPress={doDelete}>
|
||||
<Text>DELETE {whisperModel.toUpperCase()}</Text>
|
||||
</Pressable>
|
||||
) : (
|
||||
<Pressable onPress={doStopDownload}>
|
||||
<Text>PAUSE</Text>
|
||||
</Pressable>
|
||||
)
|
||||
) : (
|
||||
<Pressable onPress={doDownload}>
|
||||
{/* <Text>whisper file: { whisperFile?.tag }</Text> */}
|
||||
{whisperFile &&
|
||||
( whisperFileExists && (<Pressable onPress={doDelete} style={styles.deleteButton}>
|
||||
<Text>DELETE {whisperModel.toUpperCase()}</Text>
|
||||
</Pressable>))
|
||||
}
|
||||
<Pressable onPress={doDownload} style={styles.pauseDownloadButton}>
|
||||
<Text>DOWNLOAD {whisperModel.toUpperCase()}</Text>
|
||||
</Pressable>
|
||||
))}
|
||||
{downloadStatus?.progress && (
|
||||
{bytesDone && bytesRemaining && (
|
||||
<View>
|
||||
<Text>
|
||||
{downloadStatus.progress.current} of{" "}
|
||||
{downloadStatus.progress.total} (
|
||||
{downloadStatus.progress.percentRemaining} %){" "}
|
||||
{bytesDone} of{" "}
|
||||
{bytesRemaining} (
|
||||
{bytesDone / bytesRemaining * 100} %){" "}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
@ -1,5 +1,5 @@
|
||||
jest.mock("@/app/i18n/api", () => require("../../__mocks__/api.ts"));
|
||||
import { renderRouter} from 'expo-router/testing-library';
|
||||
import { renderRouter } from "expo-router/testing-library";
|
||||
import React from "react";
|
||||
import {
|
||||
act,
|
||||
@ -13,14 +13,21 @@ import {
|
||||
createNavigationContainerRef,
|
||||
} from "@react-navigation/native";
|
||||
import TTNavStack from "../TTNavStack";
|
||||
import { migrateDb } from "@/app/lib/db";
|
||||
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
await migrateDb("development", "up");
|
||||
// Reset the navigation state before each test
|
||||
jest.clearAllMocks();
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await migrateDb("development", "down");
|
||||
jest.clearAllMocks();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it("Navigates to ConversationThread on language selection", async () => {
|
||||
const MockComponent = jest.fn(() => <TTNavStack />);
|
||||
renderRouter(
|
||||
@ -28,7 +35,7 @@ describe("Navigation", () => {
|
||||
index: MockComponent,
|
||||
},
|
||||
{
|
||||
initialUrl: '/',
|
||||
initialUrl: "/",
|
||||
}
|
||||
);
|
||||
const languageSelectionText = await waitFor(() =>
|
||||
@ -47,14 +54,16 @@ describe("Navigation", () => {
|
||||
index: MockComponent,
|
||||
},
|
||||
{
|
||||
initialUrl: '/',
|
||||
initialUrl: "/",
|
||||
}
|
||||
);
|
||||
const settingsButton = await waitFor(() =>
|
||||
screen.getByText(/.*Settings.*/i)
|
||||
);
|
||||
fireEvent.press(settingsButton);
|
||||
expect(await waitFor(() => screen.getByText(/Settings/i))).toBeOnTheScreen();
|
||||
expect(
|
||||
await waitFor(() => screen.getByText(/Settings/i))
|
||||
).toBeOnTheScreen();
|
||||
// expect(waitFor(() => screen.getByText(/Settings/i))).toBeTruthy()
|
||||
expect(screen.getByText("Settings")).toBeOnTheScreen();
|
||||
});
|
||||
|
@ -106,7 +106,12 @@ const ISpeakButton = (props: ISpeakButtonProps) => {
|
||||
<View style={styles.flag}>
|
||||
{countries &&
|
||||
countries.map((c) => {
|
||||
return <CountryFlag isoCode={c} size={25} key={c} />;
|
||||
return (
|
||||
<View>
|
||||
<Text>{c}</Text>
|
||||
<CountryFlag isoCode={c} size={25} key={c} />
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
<View>
|
||||
@ -121,14 +126,13 @@ const ISpeakButton = (props: ISpeakButtonProps) => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
width: "20%",
|
||||
borderRadius: 10,
|
||||
borderColor: "white",
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
height: 110,
|
||||
alignSelf: "flex-start",
|
||||
margin: 8,
|
||||
width: 170,
|
||||
margin: 10,
|
||||
},
|
||||
flag: {},
|
||||
iSpeak: {
|
||||
|
@ -83,6 +83,7 @@ describe("SettingsComponent", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
db = await getDb("development");
|
||||
await migrateDb("development");
|
||||
settings = new Settings(db);
|
||||
jest.spyOn(Settings, 'getDefault').mockResolvedValue(settings);
|
||||
await settings.setHostLanguage("en");
|
||||
|
Reference in New Issue
Block a user