diff --git a/App.tsx b/App.tsx index 0fcfb58fe5..9800c978cb 100644 --- a/App.tsx +++ b/App.tsx @@ -18,6 +18,7 @@ import AppErrorBoundary, { import Main from './src/navigators/Main'; import { BottomSheetModalProvider } from '@gorhom/bottom-sheet'; import { useInitDatabase } from '@database/db'; +import { ThemeProvider } from '@hooks/persisted/useTheme'; Notifications.setNotificationHandler({ handleNotification: async () => { @@ -49,12 +50,14 @@ const App = () => { - - - -
- - + + + + +
+ + + diff --git a/__mocks__/database.js b/__mocks__/database.js index f023116ec2..103783474c 100644 --- a/__mocks__/database.js +++ b/__mocks__/database.js @@ -1,4 +1,5 @@ jest.mock('@database/queries/NovelQueries', () => ({ + getNovelById: jest.fn(), getNovelByPath: jest.fn(), deleteCachedNovels: jest.fn(), getCachedNovels: jest.fn(), @@ -30,7 +31,9 @@ jest.mock('@database/queries/ChapterQueries', () => ({ insertChapters: jest.fn(), getCustomPages: jest.fn(), getChapterCount: jest.fn(), + getChapterCountSync: jest.fn(), getPageChaptersBatched: jest.fn(), + getNovelChaptersSync: jest.fn(), getFirstUnreadChapter: jest.fn(), updateChapterProgress: jest.fn(), })); diff --git a/__tests-modules__/test-utils.tsx b/__tests-modules__/test-utils.tsx index 9e16ced519..ce0305fa04 100644 --- a/__tests-modules__/test-utils.tsx +++ b/__tests-modules__/test-utils.tsx @@ -4,6 +4,7 @@ import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { Provider as PaperProvider } from 'react-native-paper'; import { BottomSheetModalProvider } from '@gorhom/bottom-sheet'; +import { ThemeProvider } from '@hooks/persisted/useTheme'; import AppErrorBoundary from '@components/AppErrorBoundary/AppErrorBoundary'; import { NovelContextProvider } from '@screens/novel/NovelContext'; @@ -13,11 +14,13 @@ const AllTheProviders = ({ children }: { children: React.ReactElement }) => { return ( - - - {children} - - + + + + {children} + + + ); diff --git a/package.json b/package.json index 7b6e98cc11..f5ca6e0fe1 100644 --- a/package.json +++ b/package.json @@ -113,12 +113,14 @@ "react-native-screens": "^4.24.0", "react-native-shimmer-placeholder": "^2.0.9", "react-native-tab-view": "^4.3.0", + "react-native-theme-switch-animation": "^0.8.0", "react-native-url-polyfill": "^3.0.0", "react-native-webview": "^13.16.1", "react-native-worklets": "^0.8.1", "react-native-zip-archive": "^7.0.2", "sanitize-html": "^2.17.2", - "urlencode": "^2.0.0" + "urlencode": "^2.0.0", + "zustand": "^5.0.12" }, "devDependencies": { "@babel/core": "^7.29.0", @@ -145,7 +147,7 @@ "@typescript-eslint/parser": "^8.58.0", "babel-plugin-module-resolver": "^5.0.3", "babel-plugin-react-compiler": "^1.0.0", - "better-sqlite3": "^12.8.0", + "better-sqlite3": "^12.9.0", "drizzle-kit": "1.0.0-beta.20", "eslint": "^8.57.1", "eslint-plugin-eslint-comments": "^3.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01635ce04c..720c12ba6f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -79,7 +79,7 @@ importers: version: 1.11.20 drizzle-orm: specifier: 1.0.0-beta.20 - version: 1.0.0-beta.20(@op-engineering/op-sqlite@15.2.9(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@sinclair/typebox@0.34.49)(@types/better-sqlite3@7.6.13)(@types/mssql@9.1.9(@azure/core-client@1.10.1))(better-sqlite3@12.8.0)(expo-sqlite@16.0.10(expo@55.0.9)(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(mssql@11.0.1(@azure/core-client@1.10.1))(zod@4.3.6) + version: 1.0.0-beta.20(@op-engineering/op-sqlite@15.2.9(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@sinclair/typebox@0.34.49)(@types/better-sqlite3@7.6.13)(@types/mssql@9.1.9(@azure/core-client@1.10.1))(better-sqlite3@12.9.0)(expo-sqlite@16.0.10(expo@55.0.9)(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(mssql@11.0.1(@azure/core-client@1.10.1))(zod@4.3.6) expo: specifier: ^55.0.9 version: 55.0.9(@babel/core@7.29.0)(@expo/dom-webview@55.0.3)(react-native-webview@13.16.1(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4)(typescript@5.9.3) @@ -200,6 +200,9 @@ importers: react-native-tab-view: specifier: ^4.3.0 version: 4.3.0(react-native-pager-view@8.0.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) + react-native-theme-switch-animation: + specifier: ^0.8.0 + version: 0.8.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) react-native-url-polyfill: specifier: ^3.0.0 version: 3.0.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4)) @@ -218,6 +221,9 @@ importers: urlencode: specifier: ^2.0.0 version: 2.0.0 + zustand: + specifier: ^5.0.12 + version: 5.0.12(@types/react@19.2.14)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) devDependencies: '@babel/core': specifier: ^7.29.0 @@ -292,8 +298,8 @@ importers: specifier: ^1.0.0 version: 1.0.0 better-sqlite3: - specifier: ^12.8.0 - version: 12.8.0 + specifier: ^12.9.0 + version: 12.9.0 drizzle-kit: specifier: 1.0.0-beta.20 version: 1.0.0-beta.20 @@ -2410,8 +2416,8 @@ packages: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} - better-sqlite3@12.8.0: - resolution: {integrity: sha512-RxD2Vd96sQDjQr20kdP+F+dK/1OUNiVOl200vKBZY8u0vTwysfolF6Hq+3ZK2+h8My9YvZhHsF+RSGZW2VYrPQ==} + better-sqlite3@12.9.0: + resolution: {integrity: sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ==} engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x} big-integer@1.6.52: @@ -5357,6 +5363,12 @@ packages: react-native: '*' react-native-pager-view: '>= 6.0.0' + react-native-theme-switch-animation@0.8.0: + resolution: {integrity: sha512-z4f3QGSuUP4tagycls2mekng/7uxAbr75Gn0GGm7JRkrviyao++V2CtJ8VUDx+hSOsgfjEhD9D5JubsGbbHB5w==} + peerDependencies: + react: '*' + react-native: '*' + react-native-url-polyfill@3.0.0: resolution: {integrity: sha512-aA5CiuUCUb/lbrliVCJ6lZ17/RpNJzvTO/C7gC/YmDQhTUoRD5q5HlJfwLWcxz4VgAhHwXKzhxH+wUN24tAdqg==} peerDependencies: @@ -6320,6 +6332,24 @@ packages: zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zustand@5.0.12: + resolution: {integrity: sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@azure-rest/core-client@2.5.1': @@ -9189,7 +9219,7 @@ snapshots: dependencies: open: 8.4.2 - better-sqlite3@12.8.0: + better-sqlite3@12.9.0: dependencies: bindings: 1.5.0 prebuild-install: 7.1.3 @@ -9736,7 +9766,7 @@ snapshots: get-tsconfig: 4.13.7 jiti: 2.6.1 - drizzle-orm@1.0.0-beta.20(@op-engineering/op-sqlite@15.2.9(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@sinclair/typebox@0.34.49)(@types/better-sqlite3@7.6.13)(@types/mssql@9.1.9(@azure/core-client@1.10.1))(better-sqlite3@12.8.0)(expo-sqlite@16.0.10(expo@55.0.9)(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(mssql@11.0.1(@azure/core-client@1.10.1))(zod@4.3.6): + drizzle-orm@1.0.0-beta.20(@op-engineering/op-sqlite@15.2.9(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(@sinclair/typebox@0.34.49)(@types/better-sqlite3@7.6.13)(@types/mssql@9.1.9(@azure/core-client@1.10.1))(better-sqlite3@12.9.0)(expo-sqlite@16.0.10(expo@55.0.9)(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4))(mssql@11.0.1(@azure/core-client@1.10.1))(zod@4.3.6): dependencies: '@types/mssql': 9.1.9(@azure/core-client@1.10.1) mssql: 11.0.1(@azure/core-client@1.10.1) @@ -9744,7 +9774,7 @@ snapshots: '@op-engineering/op-sqlite': 15.2.9(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) '@sinclair/typebox': 0.34.49 '@types/better-sqlite3': 7.6.13 - better-sqlite3: 12.8.0 + better-sqlite3: 12.9.0 expo-sqlite: 16.0.10(expo@55.0.9)(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) zod: 4.3.6 @@ -12704,6 +12734,11 @@ snapshots: react-native-pager-view: 8.0.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4) use-latest-callback: 0.2.6(react@19.2.4) + react-native-theme-switch-animation@0.8.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4))(react@19.2.4): + dependencies: + react: 19.2.4 + react-native: 0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4) + react-native-url-polyfill@3.0.0(react-native@0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4)): dependencies: react-native: 0.83.4(@babel/core@7.29.0)(@react-native-community/cli@20.1.3(typescript@5.9.3))(@react-native/metro-config@0.83.4(@babel/core@7.29.0))(@types/react@19.2.14)(react@19.2.4) @@ -13786,3 +13821,9 @@ snapshots: zod@3.25.76: {} zod@4.3.6: {} + + zustand@5.0.12(@types/react@19.2.14)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)): + optionalDependencies: + '@types/react': 19.2.14 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) diff --git a/src/components/BottomTabBar/index.tsx b/src/components/BottomTabBar/index.tsx index 1cea197898..6a1467ffb9 100644 --- a/src/components/BottomTabBar/index.tsx +++ b/src/components/BottomTabBar/index.tsx @@ -5,6 +5,7 @@ import { Pressable, View, StyleSheet } from 'react-native'; import { Text } from 'react-native-paper'; import { ThemeColors } from '@theme/types'; import Animated from 'react-native-reanimated'; +import Color from 'color'; interface CustomBottomTabBarProps extends BottomTabBarProps { theme: ThemeColors; @@ -27,6 +28,7 @@ function CustomBottomTabBar({ showLabelsInNav, renderIcon, }: CustomBottomTabBarProps) { + const transparentBg = Color(theme.primaryContainer).fade(1).rgb().toString(); const getLabelText = useCallback( (route: any) => { if (!showLabelsInNav && route.name !== state.routeNames[state.index]) { @@ -103,7 +105,7 @@ function CustomBottomTabBar({ width: isFocused ? 64 : 32, backgroundColor: isFocused ? theme.primaryContainer - : 'transparent', + : transparentBg, }, ]} > diff --git a/src/components/ColorPickerModal/ColorPickerModal.tsx b/src/components/ColorPickerModal/ColorPickerModal.tsx index a59c7d1cc5..51723c3441 100644 --- a/src/components/ColorPickerModal/ColorPickerModal.tsx +++ b/src/components/ColorPickerModal/ColorPickerModal.tsx @@ -2,14 +2,16 @@ import React, { useState } from 'react'; import { FlatList, Pressable, StyleSheet, Text, View } from 'react-native'; import { Portal, TextInput } from 'react-native-paper'; -import { Modal } from '@components'; +import { Button, Modal } from '@components'; import { ThemeColors } from '../../theme/types'; +import { Row } from '@components/Common'; +import { getString } from '@strings/translations'; interface ColorPickerModalProps { visible: boolean; title: string; color: string; - onSubmit: (val: string) => void; + onSubmit: (val: string | undefined) => void; closeModal: () => void; theme: ThemeColors; showAccentColors?: boolean; @@ -47,6 +49,10 @@ const ColorPickerModal: React.FC = ({ setError('Enter a valid hex color code'); } }; + const onReset = () => { + onSubmit(undefined); + closeModal(); + }; const accentColors = [ '#EF5350', @@ -112,6 +118,10 @@ const ColorPickerModal: React.FC = ({ error={Boolean(error)} /> {error} + +