diff --git a/packages/app-expo/package.json b/packages/app-expo/package.json
index 8117f1158..b2ff918b8 100644
--- a/packages/app-expo/package.json
+++ b/packages/app-expo/package.json
@@ -73,6 +73,7 @@
"expo-document-picker": "~14.0.8",
"expo-file-system": "~19.0.21",
"expo-font": "~14.0.11",
+ "expo-keep-awake": "~15.0.8",
"expo-image-picker": "~17.0.11",
"expo-linear-gradient": "~15.0.8",
"expo-linking": "~8.0.11",
diff --git a/packages/app-expo/src/screens/ReaderScreen.tsx b/packages/app-expo/src/screens/ReaderScreen.tsx
index a87fe5edc..d5b76b936 100644
--- a/packages/app-expo/src/screens/ReaderScreen.tsx
+++ b/packages/app-expo/src/screens/ReaderScreen.tsx
@@ -73,6 +73,7 @@ import {
import { SafeAreaView } from "react-native-safe-area-context";
import { WebView } from "react-native-webview";
+import { ReaderKeepAwake } from "./reader/ReaderKeepAwake";
// ── Extracted modules ──
import { ReaderNoteViewModal } from "./reader/ReaderNoteViewModal";
@@ -1464,6 +1465,10 @@ export function ReaderScreen({ route, navigation }: Props) {
return (
+
;
+}
diff --git a/packages/app-expo/src/screens/reader/ReaderSettingsPanel.tsx b/packages/app-expo/src/screens/reader/ReaderSettingsPanel.tsx
index f3ae11e95..95a54af2b 100644
--- a/packages/app-expo/src/screens/reader/ReaderSettingsPanel.tsx
+++ b/packages/app-expo/src/screens/reader/ReaderSettingsPanel.tsx
@@ -41,6 +41,7 @@ export function ReaderSettingsPanel({ visible, readSettings, bookId, onClose, on
viewMode: settingViewMode,
volumeButtonsPageTurn,
smoothReading,
+ keepScreenOnWhileReading,
showTopTitleProgress,
showBottomTimeBattery,
followSystemFontScale,
@@ -297,6 +298,36 @@ export function ReaderSettingsPanel({ visible, readSettings, bookId, onClose, on
)}
+ {Platform.OS === "android" && (
+
+
+
+ {t("settings.keepScreenOnWhileReading", "Keep screen on while reading")}
+
+
+ {t(
+ "settings.keepScreenOnWhileReadingDesc",
+ "Prevent the screen from turning off while a book is open",
+ )}
+
+
+
+ onUpdateSetting("keepScreenOnWhileReading", !keepScreenOnWhileReading)
+ }
+ >
+
+ {keepScreenOnWhileReading ? t("settings.enabled") : t("settings.disabled")}
+
+
+
+ )}
{t("settings.showTopTitleProgress")}
+ readFileSync(resolve(repositoryRoot, relativePath), "utf8");
+
+describe("Android reader keep-awake setting", () => {
+ it("persists as opt-in and is exposed only in Android reader settings", () => {
+ const bookTypes = readSource("packages/core/src/types/book.ts");
+ const readerSettings = readSource(
+ "packages/app-expo/src/screens/reader/ReaderSettingsPanel.tsx",
+ );
+ const generalSettings = readSource(
+ "packages/app-expo/src/screens/settings/AppearanceSettingsScreen.tsx",
+ );
+
+ expect(bookTypes).toContain("keepScreenOnWhileReading?: boolean");
+ expect(readerSettings).toContain('Platform.OS === "android"');
+ expect(readerSettings).toContain(
+ 'onUpdateSetting("keepScreenOnWhileReading", !keepScreenOnWhileReading)',
+ );
+ expect(readerSettings.indexOf('t("settings.volumeButtonsPageTurn")')).toBeLessThan(
+ readerSettings.indexOf('t("settings.keepScreenOnWhileReading"'),
+ );
+ expect(generalSettings).not.toContain("keepScreenOnWhileReading");
+ });
+
+ it("uses the native keep-awake claim only while the reader is focused", () => {
+ const owner = readSource("packages/app-expo/src/screens/reader/ReaderKeepAwake.tsx");
+ const reader = readSource("packages/app-expo/src/screens/ReaderScreen.tsx");
+
+ expect(owner).toContain('import { useKeepAwake } from "expo-keep-awake"');
+ expect(owner).toContain('Platform.OS !== "android" || !enabled || !isFocused');
+ expect(owner).toContain('useKeepAwake("readany-reader")');
+ expect(reader).toContain("enabled={readSettings.keepScreenOnWhileReading === true}");
+ expect(reader).toContain("isFocused={isFocused}");
+ });
+});
diff --git a/packages/core/src/i18n/locales/en/settings.json b/packages/core/src/i18n/locales/en/settings.json
index 7c62a68bc..096704f23 100644
--- a/packages/core/src/i18n/locales/en/settings.json
+++ b/packages/core/src/i18n/locales/en/settings.json
@@ -74,6 +74,8 @@
"volumeButtonsPageTurnDesc": "While reading, volume keys turn pages",
"smoothReading": "Smooth Reading",
"smoothReadingDesc": "Enable page-turn transition animation and scroll inertia. Disable for better performance on low-end devices",
+ "keepScreenOnWhileReading": "Keep screen on while reading",
+ "keepScreenOnWhileReadingDesc": "Prevent the screen from turning off while a book is open",
"followSystemFontScale": "Follow System Font Scale",
"followSystemFontScaleDesc": "Auto-scale by the OS accessibility font size",
"fixedLayoutNotice": "PDF is a fixed layout format. Font and layout settings are not available.",
diff --git a/packages/core/src/i18n/locales/es/settings.json b/packages/core/src/i18n/locales/es/settings.json
index 1169f171d..5fa6d748b 100644
--- a/packages/core/src/i18n/locales/es/settings.json
+++ b/packages/core/src/i18n/locales/es/settings.json
@@ -74,6 +74,8 @@
"volumeButtonsPageTurnDesc": "Durante la lectura, los botones de volumen pasan página",
"smoothReading": "Lectura fluida",
"smoothReadingDesc": "Activa la animación de transición de página y la inercia de desplazamiento. Desactívelo para mejor rendimiento en dispositivos básicos",
+ "keepScreenOnWhileReading": "Mantener la pantalla encendida al leer",
+ "keepScreenOnWhileReadingDesc": "Evita que la pantalla se apague mientras hay un libro abierto",
"followSystemFontScale": "Seguir escala de fuente del sistema",
"followSystemFontScaleDesc": "Escalar automáticamente según el tamaño de fuente de accesibilidad del SO",
"fixedLayoutNotice": "PDF es un formato de diseño fijo. Los ajustes de fuente y diseño no están disponibles.",
diff --git a/packages/core/src/i18n/locales/fr/settings.json b/packages/core/src/i18n/locales/fr/settings.json
index 64bcde715..7c6243b6f 100644
--- a/packages/core/src/i18n/locales/fr/settings.json
+++ b/packages/core/src/i18n/locales/fr/settings.json
@@ -74,6 +74,8 @@
"volumeButtonsPageTurnDesc": "En lecture, les boutons de volume tournent les pages",
"smoothReading": "Lecture fluide",
"smoothReadingDesc": "Active l'animation de transition de page et l'inertie de défilement. Désactivez pour de meilleures performances sur les appareils modestes",
+ "keepScreenOnWhileReading": "Garder l'écran allumé pendant la lecture",
+ "keepScreenOnWhileReadingDesc": "Empêcher l'écran de s'éteindre lorsqu'un livre est ouvert",
"followSystemFontScale": "Suivre l'échelle de police système",
"followSystemFontScaleDesc": "Mise à l'échelle auto selon la taille de police d'accessibilité du système",
"fixedLayoutNotice": "Le PDF est un format à mise en page fixe. Les paramètres de police et mise en page ne sont pas disponibles.",
diff --git a/packages/core/src/i18n/locales/ja/settings.json b/packages/core/src/i18n/locales/ja/settings.json
index c89c5832a..a753c6f55 100644
--- a/packages/core/src/i18n/locales/ja/settings.json
+++ b/packages/core/src/i18n/locales/ja/settings.json
@@ -74,6 +74,8 @@
"volumeButtonsPageTurnDesc": "読書中は音量ボタンでページ送りします",
"smoothReading": "スムーズリーディング",
"smoothReadingDesc": "ページめくりアニメーションとスクロール慣性を有効化。低スペック端末ではオフにすると快適です",
+ "keepScreenOnWhileReading": "読書中は画面をオンに保つ",
+ "keepScreenOnWhileReadingDesc": "本を開いている間、画面が自動で消えないようにします",
"followSystemFontScale": "システムフォントサイズに従う",
"followSystemFontScaleDesc": "OSのアクセシビリティフォントサイズで自動調整",
"fixedLayoutNotice": "PDFは固定レイアウト形式です。フォントとレイアウト設定は利用できません。",
diff --git a/packages/core/src/i18n/locales/ko/settings.json b/packages/core/src/i18n/locales/ko/settings.json
index 18b715456..40ca1a2b6 100644
--- a/packages/core/src/i18n/locales/ko/settings.json
+++ b/packages/core/src/i18n/locales/ko/settings.json
@@ -74,6 +74,8 @@
"volumeButtonsPageTurnDesc": "독서 중 볼륨 버튼으로 페이지를 넘깁니다",
"smoothReading": "부드러운 읽기",
"smoothReadingDesc": "페이지 넘김 전환 애니메이션과 스크롤 관성을 켭니다. 저사양 기기에서는 끄면 더 부드럽습니다",
+ "keepScreenOnWhileReading": "독서 중 화면 켜짐 유지",
+ "keepScreenOnWhileReadingDesc": "책을 열어 둔 동안 화면이 자동으로 꺼지지 않게 합니다",
"followSystemFontScale": "시스템 글꼴 크기 따르기",
"followSystemFontScaleDesc": "OS 접근성 글꼴 크기에 따라 자동 조정",
"fixedLayoutNotice": "PDF는 고정 레이아웃 형식이에요. 글꼴 및 레이아웃 설정을 사용할 수 없어요.",
diff --git a/packages/core/src/i18n/locales/zh-TW/settings.json b/packages/core/src/i18n/locales/zh-TW/settings.json
index 1cb61a0ad..b4d9e212c 100644
--- a/packages/core/src/i18n/locales/zh-TW/settings.json
+++ b/packages/core/src/i18n/locales/zh-TW/settings.json
@@ -74,6 +74,8 @@
"volumeButtonsPageTurnDesc": "開啟後閱讀時音量鍵用於上下翻頁",
"smoothReading": "平滑閱讀",
"smoothReadingDesc": "開啟翻頁過渡動畫與滾動慣性,關閉可提升低效能裝置流暢度",
+ "keepScreenOnWhileReading": "閱讀時保持螢幕開啟",
+ "keepScreenOnWhileReadingDesc": "開啟書籍時防止螢幕自動關閉",
"followSystemFontScale": "跟隨系統字型大小",
"followSystemFontScaleDesc": "按系統輔助功能字型大小自動放大",
"fixedLayoutNotice": "PDF 為固定排版格式,字型和排版設定不可用。",
diff --git a/packages/core/src/i18n/locales/zh/settings.json b/packages/core/src/i18n/locales/zh/settings.json
index 508744bc6..18b4643ed 100644
--- a/packages/core/src/i18n/locales/zh/settings.json
+++ b/packages/core/src/i18n/locales/zh/settings.json
@@ -74,6 +74,8 @@
"volumeButtonsPageTurnDesc": "开启后阅读时音量键用于上下翻页",
"smoothReading": "平滑阅读",
"smoothReadingDesc": "开启翻页过渡动画与滚动惯性,关闭可提升低性能设备流畅度",
+ "keepScreenOnWhileReading": "阅读时保持屏幕常亮",
+ "keepScreenOnWhileReadingDesc": "打开书籍时防止屏幕自动关闭",
"followSystemFontScale": "跟随系统字号",
"followSystemFontScaleDesc": "按系统辅助功能字号自动放大",
"fixedLayoutNotice": "PDF 为固定布局格式,字体和排版设置不可用。",
diff --git a/packages/core/src/types/book.ts b/packages/core/src/types/book.ts
index f20703d71..017940226 100644
--- a/packages/core/src/types/book.ts
+++ b/packages/core/src/types/book.ts
@@ -96,6 +96,8 @@ export interface ReadSettings extends ViewSettings {
showTopTitleProgress: boolean;
showBottomTimeBattery: boolean;
volumeButtonsPageTurn: boolean;
+ /** Android-only: keep the display awake while the reader screen is focused. */
+ keepScreenOnWhileReading?: boolean;
defaultHighlightColor?: HighlightColor;
/**
* Mobile-only opt-in: smooth reading — enables the foliate `animated`
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 560ef437a..0c85c158a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -340,6 +340,9 @@ importers:
expo-font:
specifier: ~14.0.11
version: 14.0.11(expo@54.0.33(@babel/core@7.29.0)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
+ expo-keep-awake:
+ specifier: ~15.0.8
+ version: 15.0.8(expo@54.0.33(@babel/core@7.29.0)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react@19.1.0)
expo-image-picker:
specifier: ~17.0.11
version: 17.0.11(expo@54.0.33(@babel/core@7.29.0)(graphql@16.8.1)(react-native-webview@13.15.0(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))