Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions packages/app-expo/src/lib/platform/expo-platform-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,16 @@ export class ExpoPlatformService implements IPlatformService {
// ---- File system (expo-file-system v55 — File/Directory/Paths API) ----

async readFile(path: string): Promise<Uint8Array> {
const file = new File(path);
return file.bytes();
try {
const file = new File(path);
return await file.bytes();
} catch (err) {
if (!path.startsWith("content://")) throw err;
const base64 = await LegacyFS.readAsStringAsync(path, {
encoding: LegacyFS.EncodingType.Base64,
});
return base64ToBytes(base64);
}
}

async writeFile(path: string, data: Uint8Array): Promise<void> {
Expand Down Expand Up @@ -838,6 +846,15 @@ export class ExpoPlatformService implements IPlatformService {
}
}

function base64ToBytes(base64: string): Uint8Array {
const binary = atob(base64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return bytes;
}

/** Map book file extensions to MIME types for document picker */
function extensionToMime(ext: string): string {
const map: Record<string, string> = {
Expand Down
23 changes: 13 additions & 10 deletions packages/app-expo/src/screens/ReaderScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ const NOTE_TOOLTIP_SIDE_PADDING = 12;
const NOTE_TOOLTIP_ABOVE_OFFSET = 2;
const NOTE_TOOLTIP_BELOW_OFFSET = 8;
const NOTE_TOOLTIP_TOP_THRESHOLD = 180;
import { useRubyStore } from "@readany/core/stores/ruby-store";
import { ReaderSettingsPanel } from "./reader/ReaderSettingsPanel";
import { ReaderTOCPanel } from "./reader/ReaderTOCPanel";
import {
Expand All @@ -159,7 +160,6 @@ import { useReaderSearch } from "./reader/useReaderSearch";
import { useReaderSystemInfo } from "./reader/useReaderSystemInfo";
import { useReaderTTS } from "./reader/useReaderTTS";
import { useVolumeButtonPaging } from "./reader/useVolumeButtonPaging";
import { useRubyStore } from "@readany/core/stores/ruby-store";

const READER_HTML_ASSET = Asset.fromModule(require("../../assets/reader/reader.html"));
const LOCAL_FONT_SERVER_DIR = "readany-fonts";
Expand Down Expand Up @@ -333,8 +333,8 @@ export function ReaderScreen({ route, navigation }: Props) {
const customFonts = useFontStore((s) => s.fonts);
const selectedFontId = useFontStore((s) => s.selectedFontId);
const customFontFamily = useMemo(() => {
if (!selectedFontId) return undefined;
return customFonts.find((f) => f.id === selectedFontId)?.fontFamily;
if (!selectedFontId) return "";
return customFonts.find((f) => f.id === selectedFontId)?.fontFamily ?? "";
}, [customFonts, selectedFontId]);
const customFontFaceCSS = useMemo(
() => buildCustomFontFaceCSS(customFonts, selectedFontId, fontServerUrl),
Expand Down Expand Up @@ -571,7 +571,7 @@ export function ReaderScreen({ route, navigation }: Props) {
const settings = useSettingsStore.getState().readSettings;
const { fonts, selectedFontId: selId } = useFontStore.getState();
const fontCSS = buildCustomFontFaceCSS(fonts, selId, fileServerRef.current);
const fontFamily = selId ? fonts.find((f) => f.id === selId)?.fontFamily : undefined;
const fontFamily = selId ? fonts.find((f) => f.id === selId)?.fontFamily : "";
console.log("[ReaderScreen][Font] selection", {
selectedFontId: selId,
fontFamily,
Expand All @@ -586,15 +586,17 @@ export function ReaderScreen({ route, navigation }: Props) {
viewMode: settings.viewMode,
paginatedLayout: settings.paginatedLayout,
customFontFaceCSS: fontCSS,
customFontFamily: fontFamily,
customFontFamily: fontFamily ?? "",
});

// Auto-restore ruby annotations if enabled for this book
const rubyMode = useRubyStore.getState().getBookRuby(bookId);
if (rubyMode) {
void (async () => {
try {
const { checkExistingDictMobile, readDictStrings } = await import("@/lib/ruby/dict-service-mobile");
const { checkExistingDictMobile, readDictStrings } = await import(
"@/lib/ruby/dict-service-mobile"
);
const exists = await checkExistingDictMobile();
if (exists) {
const { wordDict, charDict } = await readDictStrings();
Expand Down Expand Up @@ -961,15 +963,15 @@ export function ReaderScreen({ route, navigation }: Props) {
const currentSettings = useSettingsStore.getState().readSettings;
const { fonts, selectedFontId: selId } = useFontStore.getState();
const fontCSS = buildCustomFontFaceCSS(fonts, selId, fileServerRef.current);
const fontFamily = selId ? fonts.find((f) => f.id === selId)?.fontFamily : undefined;
const fontFamily = selId ? fonts.find((f) => f.id === selId)?.fontFamily : "";
// Recompute effective fontSize after every settings change — covers
// both stepper changes and toggling followSystemFontScale on/off.
const merged = { ...currentSettings, ...updates };
bridge.applySettings({
...merged,
fontSize: computeEffectiveFontSize(merged.fontSize, merged.followSystemFontScale),
customFontFaceCSS: fontCSS,
customFontFamily: fontFamily,
customFontFamily: fontFamily ?? "",
});
},
[bridge, updateReadSettings, computeEffectiveFontSize],
Expand Down Expand Up @@ -1412,8 +1414,9 @@ export function ReaderScreen({ route, navigation }: Props) {

const isPanelOpen = showTOC || showSettings || showSearch || showNotebook || showTranslation;
const existingSelectionHighlight = selection
? (highlights.find((highlight) => highlight.bookId === bookId && highlight.cfi === selection.cfi) ??
null)
? (highlights.find(
(highlight) => highlight.bookId === bookId && highlight.cfi === selection.cfi,
) ?? null)
: null;
const readerTopMargin = !showSearch
? showTopTitleProgress
Expand Down
Loading