refactor: Reader Settings Screen
This commit is contained in:
@@ -12,6 +12,7 @@ module.exports = function (api) {
|
||||
'@hooks': './src/hooks',
|
||||
'@screens': './src/screens',
|
||||
'@strings': './strings',
|
||||
'@redux': './src/redux',
|
||||
},
|
||||
extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],
|
||||
},
|
||||
|
||||
@@ -79,7 +79,7 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 16,
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
outlined: {
|
||||
borderWidth: 1,
|
||||
|
||||
+28
-15
@@ -2,33 +2,46 @@ import React, { useState } from 'react';
|
||||
import { FlatList, Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import { Modal, Portal, TextInput } from 'react-native-paper';
|
||||
import { ThemeType } from '../../theme/types';
|
||||
|
||||
const ColorPickerModal = ({
|
||||
interface ColorPickerModalProps {
|
||||
visible: boolean;
|
||||
title: string;
|
||||
color: string;
|
||||
onSubmit: (val: string) => void;
|
||||
closeModal: () => void;
|
||||
theme: ThemeType;
|
||||
showAccentColors?: boolean;
|
||||
}
|
||||
|
||||
const ColorPickerModal: React.FC<ColorPickerModalProps> = ({
|
||||
theme,
|
||||
color,
|
||||
title,
|
||||
onSubmit,
|
||||
hideModal,
|
||||
modalVisible,
|
||||
closeModal,
|
||||
visible,
|
||||
showAccentColors,
|
||||
}) => {
|
||||
const [text, setText] = useState(color);
|
||||
const [error, setError] = useState();
|
||||
const [text, setText] = useState<string>(color);
|
||||
const [error, setError] = useState<string | null>();
|
||||
|
||||
const onDismiss = () => {
|
||||
hideModal();
|
||||
setText();
|
||||
setError();
|
||||
closeModal();
|
||||
if (error) {
|
||||
setText(color);
|
||||
}
|
||||
setError(null);
|
||||
};
|
||||
|
||||
const onChangeText = txt => setText(txt);
|
||||
const onChangeText = (txt: string) => setText(txt);
|
||||
|
||||
const onSubmitEditing = () => {
|
||||
const re = /^#([0-9a-f]{6}|[0-9a-f]{3})$/i;
|
||||
const re = /^#([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{3})$/i;
|
||||
|
||||
if (text.match(re)) {
|
||||
onSubmit(text);
|
||||
hideModal();
|
||||
closeModal();
|
||||
} else {
|
||||
setError('Enter a valid hex color code');
|
||||
}
|
||||
@@ -69,7 +82,7 @@ const ColorPickerModal = ({
|
||||
return (
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={modalVisible}
|
||||
visible={visible}
|
||||
onDismiss={onDismiss}
|
||||
contentContainerStyle={[
|
||||
styles.modalContainer,
|
||||
@@ -79,7 +92,7 @@ const ColorPickerModal = ({
|
||||
<Text style={[styles.modalTitle, { color: theme.textColorPrimary }]}>
|
||||
{title}
|
||||
</Text>
|
||||
{showAccentColors && (
|
||||
{showAccentColors ? (
|
||||
<FlatList
|
||||
contentContainerStyle={{ marginBottom: 8 }}
|
||||
data={accentColors}
|
||||
@@ -110,7 +123,7 @@ const ColorPickerModal = ({
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
) : null}
|
||||
<TextInput
|
||||
value={text}
|
||||
defaultValue={color}
|
||||
@@ -121,7 +134,7 @@ const ColorPickerModal = ({
|
||||
theme={textInputTheme}
|
||||
underlineColor={theme.textColorHint}
|
||||
dense
|
||||
error={error}
|
||||
error={Boolean(error)}
|
||||
/>
|
||||
<Text style={styles.errorText}>{error}</Text>
|
||||
</Modal>
|
||||
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import { ThemeType } from '../../theme/types';
|
||||
|
||||
interface ColorPreferenceItemProps {
|
||||
label: string;
|
||||
description?: string;
|
||||
onPress: () => void;
|
||||
theme: ThemeType;
|
||||
}
|
||||
|
||||
const ColorPreferenceItem: React.FC<ColorPreferenceItemProps> = ({
|
||||
label,
|
||||
description,
|
||||
theme,
|
||||
onPress,
|
||||
}) => (
|
||||
<Pressable
|
||||
style={styles.container}
|
||||
android_ripple={{ color: theme.rippleColor }}
|
||||
onPress={onPress}
|
||||
>
|
||||
<View>
|
||||
<Text style={[styles.label, { color: theme.textColorPrimary }]}>
|
||||
{label}
|
||||
</Text>
|
||||
<Text style={{ color: theme.textColorSecondary }}>
|
||||
{description?.toUpperCase()}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={[{ backgroundColor: description }, styles.colorPreview]} />
|
||||
</Pressable>
|
||||
);
|
||||
|
||||
export default ColorPreferenceItem;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
label: {
|
||||
fontSize: 16,
|
||||
},
|
||||
colorPreview: {
|
||||
height: 24,
|
||||
width: 24,
|
||||
borderRadius: 50,
|
||||
marginRight: 16,
|
||||
},
|
||||
});
|
||||
@@ -52,10 +52,10 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
labelContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
label: {
|
||||
fontSize: 16,
|
||||
textAlignVertical: 'center',
|
||||
},
|
||||
switch: {
|
||||
marginLeft: 8,
|
||||
|
||||
@@ -10,3 +10,4 @@ export { default as Button } from './Button/Button';
|
||||
export { default as Appbar } from './Appbar/Appbar';
|
||||
export { default as SwitchItem } from './SwitchItem/SwitchItem';
|
||||
export { default as List } from './List/List';
|
||||
export { default as ColorPreferenceItem } from './ColorPreferenceItem/ColorPreferenceItem';
|
||||
|
||||
@@ -4,15 +4,15 @@ import { createStackNavigator } from '@react-navigation/stack';
|
||||
|
||||
// Screens
|
||||
import About from '../screens/more/About';
|
||||
import Settings from '../screens/setting/SettingsScreen';
|
||||
import TrackerSettings from '../screens/setting/SettingsTrackerScreen';
|
||||
import ReaderSettings from '../screens/setting/SettingsReaderScreen';
|
||||
import BackupSettings from '../screens/setting/SettingsBackupScreen';
|
||||
import AdvancedSettings from '../screens/setting/SettingsAdvancedScreen';
|
||||
import GeneralSettings from '../screens/setting/SettingsGeneralScreen';
|
||||
import Settings from '../screens/settings/SettingsScreen';
|
||||
import TrackerSettings from '../screens/settings/SettingsTrackerScreen';
|
||||
import ReaderSettings from '../screens/settings/SettingsReaderScreen/SettingsReaderScreen';
|
||||
import BackupSettings from '../screens/settings/SettingsBackupScreen';
|
||||
import AdvancedSettings from '../screens/settings/SettingsAdvancedScreen';
|
||||
import GeneralSettings from '../screens/settings/SettingsGeneralScreen';
|
||||
import DownloadQueue from '../screens/more/DownloadQueueScreen';
|
||||
import Downloads from '../screens/more/DownloadsScreen';
|
||||
import AppearanceSettings from '../screens/setting/SettingsAppearanceScreen';
|
||||
import AppearanceSettings from '../screens/settings/SettingsAppearanceScreen';
|
||||
|
||||
const Stack = createStackNavigator();
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ const themes = {
|
||||
* 3 -> No title
|
||||
*/
|
||||
|
||||
const initialState = {
|
||||
export const initialState = {
|
||||
/**
|
||||
* General settings
|
||||
*/
|
||||
@@ -113,6 +113,7 @@ const initialState = {
|
||||
showBatteryAndTime: false,
|
||||
autoScroll: false,
|
||||
autoScrollInterval: 10,
|
||||
autoScrollOffset: null,
|
||||
textSelectable: false,
|
||||
verticalSeekbar: true,
|
||||
|
||||
|
||||
@@ -78,6 +78,7 @@ const HistoryScreen = () => {
|
||||
novelName: string,
|
||||
chapterId: number,
|
||||
chapterUrl: string,
|
||||
chapterName: string,
|
||||
bookmark: number,
|
||||
) =>
|
||||
navigate(
|
||||
@@ -89,6 +90,7 @@ const HistoryScreen = () => {
|
||||
chapterId,
|
||||
chapterUrl,
|
||||
bookmark,
|
||||
chapterName,
|
||||
} as never,
|
||||
);
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ interface HistoryCardProps {
|
||||
novelName: string,
|
||||
chapterId: number,
|
||||
chapterUrl: string,
|
||||
chapterName: string,
|
||||
isBookmarked: number,
|
||||
) => void;
|
||||
handleRemoveFromHistory: (historyId: number) => void;
|
||||
@@ -105,6 +106,7 @@ const HistoryCard: React.FC<HistoryCardProps> = ({
|
||||
novelName,
|
||||
chapterId,
|
||||
chapterUrl,
|
||||
chapterName,
|
||||
bookmark,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ import { useFullscreenMode } from '../../hooks';
|
||||
import { getChapterFromDb } from '../../database/queries/DownloadQueries';
|
||||
import ReaderBottomSheetV2 from './components/ReaderBottomSheet/ReaderBottomSheet';
|
||||
import { useReaderSettings } from '../../redux/hooks';
|
||||
import { defaultTo } from 'lodash';
|
||||
|
||||
const Chapter = ({ route, navigation }) => {
|
||||
useKeepAwake();
|
||||
@@ -84,6 +85,7 @@ const Chapter = ({ route, navigation }) => {
|
||||
showBatteryAndTime = false,
|
||||
autoScroll = false,
|
||||
autoScrollInterval = 10,
|
||||
autoScrollOffset = null,
|
||||
verticalSeekbar = true,
|
||||
} = useSettings();
|
||||
|
||||
@@ -182,11 +184,15 @@ const Chapter = ({ route, navigation }) => {
|
||||
scrollTimeout = setTimeout(() => {
|
||||
scrollViewRef.current.scrollTo({
|
||||
x: 0,
|
||||
y: currentOffset + Dimensions.get('window').height,
|
||||
y:
|
||||
currentOffset +
|
||||
defaultTo(autoScrollOffset, Dimensions.get('window').height),
|
||||
animated: true,
|
||||
});
|
||||
setCurrentOffset(
|
||||
prevState => prevState + Dimensions.get('window').height,
|
||||
prevState =>
|
||||
prevState +
|
||||
defaultTo(autoScrollOffset, Dimensions.get('window').height),
|
||||
);
|
||||
}, autoScrollInterval * 1000);
|
||||
}
|
||||
@@ -289,13 +295,6 @@ const Chapter = ({ route, navigation }) => {
|
||||
})
|
||||
: showToast("There's no next chapter");
|
||||
|
||||
const enableSwipeGestures = () => {
|
||||
dispatch(setAppSettings('swipeGestures', !swipeGestures));
|
||||
showToast(
|
||||
swipeGestures ? 'Swipe gestures disabled' : 'Swipe gestured enabled',
|
||||
);
|
||||
};
|
||||
|
||||
const enableAutoScroll = () =>
|
||||
dispatch(setAppSettings('autoScroll', !autoScroll));
|
||||
|
||||
@@ -408,7 +407,7 @@ const Chapter = ({ route, navigation }) => {
|
||||
<TextReader
|
||||
text={chapter.chapterText}
|
||||
reader={readerSettings}
|
||||
chapterName={chapterName || chapter.chapterName}
|
||||
chapterName={chapter.chapterName || chapterName}
|
||||
textSelectable={textSelectable}
|
||||
theme={theme}
|
||||
nextChapter={nextChapter}
|
||||
|
||||
@@ -155,7 +155,7 @@ const ReaderBottomSheetV2: React.FC<ReaderBottomSheetV2Props> = ({
|
||||
() => [
|
||||
{
|
||||
key: 'first',
|
||||
title: getString('moreScreen.settingsScreen.readerSettings'),
|
||||
title: getString('moreScreen.settingsScreen.readerSettings.title'),
|
||||
},
|
||||
{
|
||||
key: 'second',
|
||||
|
||||
@@ -33,7 +33,14 @@ const ReaderFontPicker = () => {
|
||||
{readerFonts.map(item => (
|
||||
<View
|
||||
key={item.fontFamily}
|
||||
style={[styles.container, { backgroundColor: theme.rippleColor }]}
|
||||
style={[
|
||||
styles.container,
|
||||
{
|
||||
backgroundColor: isSelected(item)
|
||||
? theme.rippleColor
|
||||
: theme.searchBarColor,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
style={styles.content}
|
||||
@@ -57,8 +64,8 @@ const ReaderFontPicker = () => {
|
||||
color: isSelected(item)
|
||||
? theme.colorAccent
|
||||
: theme.textColorPrimary,
|
||||
marginLeft: isSelected(item) ? 4 : 0,
|
||||
},
|
||||
isSelected(item) && styles.mLeft,
|
||||
]}
|
||||
>
|
||||
{item.name}
|
||||
@@ -102,4 +109,7 @@ const styles = StyleSheet.create({
|
||||
label: {
|
||||
fontSize: 16,
|
||||
},
|
||||
mLeft: {
|
||||
marginLeft: 4,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { StyleSheet, Text, TextStyle, View } from 'react-native';
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
@@ -10,7 +10,11 @@ import { IconButtonV2 } from '../../../../components';
|
||||
import { setReaderSettings } from '../../../../redux/settings/settings.actions';
|
||||
import { getString } from '../../../../../strings/translations';
|
||||
|
||||
const ReaderLineHeight = () => {
|
||||
interface ReaderLineHeightProps {
|
||||
labelStyle?: TextStyle | TextStyle[];
|
||||
}
|
||||
|
||||
const ReaderLineHeight: React.FC<ReaderLineHeightProps> = ({ labelStyle }) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@@ -18,7 +22,7 @@ const ReaderLineHeight = () => {
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={{ color: theme.textColorSecondary }}>
|
||||
<Text style={[{ color: theme.textColorSecondary }, labelStyle]}>
|
||||
{getString('readerScreen.bottomSheet.lineHeight')}
|
||||
</Text>
|
||||
<View style={styles.buttonContainer}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import { StyleSheet, Text, TextStyle, View } from 'react-native';
|
||||
import React from 'react';
|
||||
|
||||
import { setReaderSettings } from '../../../../redux/settings/settings.actions';
|
||||
@@ -11,7 +11,13 @@ import { textAlignments } from '../../../../utils/constants/readerConstants';
|
||||
import { ToggleButton } from '../../../../components/Common/ToggleButton';
|
||||
import { getString } from '../../../../../strings/translations';
|
||||
|
||||
const ReaderTextAlignSelector = () => {
|
||||
interface ReaderTextAlignSelectorProps {
|
||||
labelStyle?: TextStyle | TextStyle[];
|
||||
}
|
||||
|
||||
const ReaderTextAlignSelector: React.FC<ReaderTextAlignSelectorProps> = ({
|
||||
labelStyle,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@@ -19,7 +25,7 @@ const ReaderTextAlignSelector = () => {
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={{ color: theme.textColorSecondary }}>
|
||||
<Text style={[{ color: theme.textColorSecondary }, labelStyle]}>
|
||||
{getString('readerScreen.bottomSheet.textAlign')}
|
||||
</Text>
|
||||
<View style={styles.buttonContainer}>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ScrollView, StyleSheet, Text, View } from 'react-native';
|
||||
import { ScrollView, StyleSheet, Text, TextStyle, View } from 'react-native';
|
||||
import React from 'react';
|
||||
import { presetReaderThemes } from '../../../../theme/reader/presets';
|
||||
import { setReaderSettings } from '../../../../redux/settings/settings.actions';
|
||||
import {
|
||||
useAppDispatch,
|
||||
@@ -10,8 +9,17 @@ import {
|
||||
} from '../../../../redux/hooks';
|
||||
import { ToggleColorButton } from '../../../../components/Common/ToggleButton';
|
||||
import { getString } from '../../../../../strings/translations';
|
||||
import { presetReaderThemes } from '../../../../utils/constants/readerConstants';
|
||||
|
||||
const ReaderThemeSelector = () => {
|
||||
interface ReaderThemeSelectorProps {
|
||||
label?: string;
|
||||
labelStyle?: TextStyle | TextStyle[];
|
||||
}
|
||||
|
||||
const ReaderThemeSelector: React.FC<ReaderThemeSelectorProps> = ({
|
||||
label,
|
||||
labelStyle,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const theme = useTheme();
|
||||
const {
|
||||
@@ -22,10 +30,16 @@ const ReaderThemeSelector = () => {
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={[{ color: theme.textColorSecondary }, styles.title]}>
|
||||
{getString('readerScreen.bottomSheet.color')}
|
||||
<Text
|
||||
style={[{ color: theme.textColorSecondary }, styles.title, labelStyle]}
|
||||
>
|
||||
{label || getString('readerScreen.bottomSheet.color')}
|
||||
</Text>
|
||||
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
|
||||
<ScrollView
|
||||
horizontal={true}
|
||||
contentContainerStyle={styles.scrollView}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
>
|
||||
{[...customThemes, ...presetReaderThemes].map((item, index) => (
|
||||
<ToggleColorButton
|
||||
key={index}
|
||||
@@ -59,4 +73,8 @@ const styles = StyleSheet.create({
|
||||
title: {
|
||||
marginRight: 16,
|
||||
},
|
||||
scrollView: {
|
||||
flexGrow: 1,
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,628 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
Pressable,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
KeyboardAvoidingView,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { IconButton } from 'react-native-paper';
|
||||
import WebView from 'react-native-webview';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { Appbar } from '../../components/Appbar';
|
||||
import ColorPickerModal from '../../components/ColorPickerModal';
|
||||
import { Row } from '../../components/Common';
|
||||
import {
|
||||
ToggleButton,
|
||||
ToggleColorButton,
|
||||
} from '../../components/Common/ToggleButton';
|
||||
import { List } from '../../components/List';
|
||||
|
||||
import { useSettings, useTheme } from '../../hooks/reduxHooks';
|
||||
import {
|
||||
setAppSettings,
|
||||
setReaderSettings,
|
||||
} from '../../redux/settings/settings.actions';
|
||||
import {
|
||||
readerBackground,
|
||||
readerLineHeight,
|
||||
readerTextColor,
|
||||
} from '../reader/utils/readerStyles';
|
||||
import { useModal } from '../../hooks/useModal';
|
||||
import SwitchSetting from '../../components/Switch/Switch';
|
||||
import FontPickerModal from './components/FontPickerModal';
|
||||
import { fonts } from '../../services/utils/constants';
|
||||
import { useReaderSettings, useSettingsV2 } from '../../redux/hooks';
|
||||
import { Button } from '@components/index';
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
import {
|
||||
deleteCustomReaderTheme,
|
||||
saveCustomReaderTheme,
|
||||
} from '../../redux/settings/settingsSlice';
|
||||
|
||||
const presetThemes = [
|
||||
{
|
||||
backgroundColor: '#000000',
|
||||
textColor: 'rgba(255,255,255,0.7)',
|
||||
},
|
||||
{ backgroundColor: '#FFFFFF', textColor: '#111111' },
|
||||
{ backgroundColor: '#F7DFC6', textColor: '#593100' },
|
||||
{ backgroundColor: '#292832', textColor: '#CCCCCC' },
|
||||
{ backgroundColor: '#2B2C30', textColor: '#CCCCCC' },
|
||||
];
|
||||
|
||||
const textAlignments = [
|
||||
{ value: 'left', icon: 'format-align-left' },
|
||||
{ value: 'center', icon: 'format-align-center' },
|
||||
{ value: 'justify', icon: 'format-align-justify' },
|
||||
{ value: 'right', icon: 'format-align-right' },
|
||||
];
|
||||
|
||||
const SettingsReaderScreen = ({ navigation }) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const reader = useReaderSettings();
|
||||
|
||||
const {
|
||||
reader: { customThemes = [] },
|
||||
} = useSettingsV2();
|
||||
|
||||
const {
|
||||
useWebViewForChapter = false,
|
||||
verticalSeekbar = true,
|
||||
swipeGestures = true,
|
||||
fullScreenMode = true,
|
||||
showScrollPercentage = true,
|
||||
showBatteryAndTime = false,
|
||||
autoScrollInterval = 10,
|
||||
} = useSettings();
|
||||
|
||||
const readerFontPickerModal = useModal();
|
||||
const readerBackgroundModal = useModal();
|
||||
const readerTextColorModal = useModal();
|
||||
|
||||
const setReaderBackground = val => {
|
||||
dispatch(setReaderSettings('theme', val));
|
||||
};
|
||||
|
||||
const setReaderTextColor = val => {
|
||||
dispatch(setReaderSettings('textColor', val ?? reader.textColor));
|
||||
};
|
||||
|
||||
const [customCSS, setcustomCSS] = useState(reader.customCSS);
|
||||
|
||||
const readerThemes = [...customThemes, ...presetThemes];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar title="Reader" onBackAction={navigation.goBack} />
|
||||
<KeyboardAvoidingView style={{ flex: 1 }} behavior="padding">
|
||||
<ScrollView
|
||||
style={{ flex: 1 }}
|
||||
contentContainerStyle={{ paddingBottom: 40 }}
|
||||
>
|
||||
{useWebViewForChapter ? (
|
||||
<WebView
|
||||
originWhitelist={['*']}
|
||||
style={{
|
||||
height: 500,
|
||||
backgroundColor: readerBackground(reader.theme),
|
||||
}}
|
||||
nestedScrollEnabled={true}
|
||||
source={{
|
||||
html: `
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||
<style>
|
||||
body {
|
||||
color: ${reader.textColor};
|
||||
text-align: ${reader.textAlign};
|
||||
line-height: ${reader.lineHeight};
|
||||
font-size: ${reader.textSize}px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
padding-left: ${reader.padding}%;
|
||||
padding-right: ${reader.padding}%;
|
||||
font-family: ${reader.fontFamily};
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
|
||||
${reader.customCSS}
|
||||
|
||||
@font-face {
|
||||
font-family: ${reader.fontFamily};
|
||||
src: url("file:///android_asset/fonts/${reader.fontFamily}.ttf");
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean lobortis, diam sed malesuada bibendum, nulla libero scelerisque sapien, nec interdum nisl ipsum ac ipsum. In lacinia eros ut quam commodo, in finibus augue ultricies. Vestibulum ex purus, condimentum eget sem at, molestie semper mi. Mauris ac feugiat quam. Pellentesque sagittis bibendum nibh eu lacinia. Aenean rhoncus, velit sit amet mollis egestas, diam turpis ornare velit, a dictum elit velit in erat. Quisque luctus in sem a vulputate.
|
||||
</p>
|
||||
<p> Pellentesque id tempus orci, non finibus tortor. Suspendisse in neque non eros eleifend hendrerit vitae a lacus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nunc interdum magna nulla, eget pharetra arcu dapibus eu. Pellentesque sed lectus sit amet sem porta lacinia. Curabitur consectetur dolor in nibh varius, ac placerat erat pellentesque. Proin in justo condimentum, fermentum lacus eget, ultrices ante. Fusce tempor blandit erat nec mollis. Vivamus in leo et nunc consectetur elementum nec ac lectus.
|
||||
</p>
|
||||
<p> In consectetur libero tempor metus interdum, sit amet viverra leo dapibus. Nullam tincidunt justo hendrerit lorem maximus, eu pretium erat fringilla. Nulla scelerisque leo at enim convallis, a elementum velit laoreet. Aliquam quis vestibulum quam. Morbi ut sollicitudin mi, et laoreet elit. Vivamus mattis, nulla at blandit sodales, lectus lacus luctus metus, non euismod neque urna vel nisl. Quisque vitae ante vitae orci tempus egestas quis eu nibh. Phasellus eget nulla non velit tincidunt fringilla eget nec libero. Morbi tempor erat quis rutrum condimentum.
|
||||
</p>
|
||||
<p> Cras sem magna, tempus sed urna eget, scelerisque tincidunt tortor. Cras euismod turpis libero, ut condimentum nulla ultrices id. Phasellus faucibus, elit ut imperdiet euismod, enim dui volutpat turpis, in tincidunt ex ligula non felis. Praesent erat erat, ultrices ut imperdiet sed, congue eu leo. Aliquam viverra fringilla ultrices. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent ac malesuada massa. Cras eu augue in dui venenatis laoreet sit amet eget sem. Nullam malesuada sapien felis, et varius neque auctor eu.
|
||||
</p>
|
||||
<p> Sed vestibulum facilisis libero, in aliquet mauris lobortis et. In vitae lectus id risus cursus dictum at ac mi. Praesent ac lectus eget nunc elementum pellentesque. Ut at dui magna. Aliquam mattis posuere gravida. Morbi volutpat, dolor quis varius tincidunt, quam nulla vulputate libero, eu sagittis dui odio et magna. Sed luctus lectus ante, sit amet ultrices ligula convallis vitae. Sed efficitur libero nec quam porta, et fringilla turpis egestas. Nulla facilisi. Duis leo tellus, porta non enim eu, tincidunt cursus lorem.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: readerBackground(reader.theme),
|
||||
padding: `${reader.padding}%`,
|
||||
height: 500,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
color: reader.textColor,
|
||||
fontSize: reader.textSize,
|
||||
lineHeight: readerLineHeight(
|
||||
reader.textSize,
|
||||
reader.lineHeight,
|
||||
),
|
||||
fontFamily: reader.fontFamily,
|
||||
}}
|
||||
>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean
|
||||
lobortis, diam sed malesuada bibendum, nulla libero scelerisque
|
||||
sapien, nec interdum nisl ipsum ac ipsum. In lacinia eros ut
|
||||
quam commodo, in finibus augue ultricies. Vestibulum ex purus,
|
||||
condimentum eget sem at, molestie semper mi. Mauris ac feugiat
|
||||
quam. Pellentesque sagittis bibendum nibh eu lacinia. Aenean
|
||||
rhoncus, velit sit amet mollis egestas, diam turpis ornare
|
||||
velit, a dictum elit velit in erat. Quisque luctus in sem a
|
||||
vulputate.{'\n\n'}Pellentesque id tempus orci, non finibus
|
||||
tortor. Suspendisse in neque non eros eleifend hendrerit vitae a
|
||||
lacus. Vestibulum ante ipsum primis in faucibus orci luctus et
|
||||
ultrices posuere cubilia curae; Nunc interdum magna nulla, eget
|
||||
pharetra arcu dapibus eu. Pellentesque sed lectus sit amet sem
|
||||
porta lacinia. Curabitur consectetur dolor in nibh varius, ac
|
||||
placerat erat pellentesque. Proin in justo condimentum,
|
||||
fermentum lacus eget, ultrices ante. Fusce tempor blandit erat
|
||||
nec mollis. Vivamus in leo et nunc consectetur elementum nec ac
|
||||
lectus.
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
<SwitchSetting
|
||||
label="Render HTML"
|
||||
description="Render chapter as html"
|
||||
value={useWebViewForChapter}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
setAppSettings('useWebViewForChapter', !useWebViewForChapter),
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<SwitchSetting
|
||||
label="Horizontal seekbar"
|
||||
description="Show horizontal seekbar instead of vertical"
|
||||
value={verticalSeekbar}
|
||||
onPress={() =>
|
||||
dispatch(setAppSettings('verticalSeekbar', !verticalSeekbar))
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<SwitchSetting
|
||||
label="Gesture navigation"
|
||||
description="Use left and right swipe to navigate to previous or next chapter"
|
||||
value={swipeGestures}
|
||||
onPress={() =>
|
||||
dispatch(setAppSettings('swipeGestures', !swipeGestures))
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<List.Divider theme={theme} />
|
||||
<List.SubHeader theme={theme}>
|
||||
Auto scroll interval (in seconds)
|
||||
</List.SubHeader>
|
||||
<View style={{ paddingHorizontal: 16, paddingBottom: 8 }}>
|
||||
<TextInput
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontSize: 16,
|
||||
}}
|
||||
defaultValue={autoScrollInterval.toString() ?? 10}
|
||||
keyboardType="numeric"
|
||||
onChangeText={text =>
|
||||
text !== '' &&
|
||||
dispatch(
|
||||
setAppSettings('autoScrollInterval', parseInt(text, 10)),
|
||||
)
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
<List.Divider theme={theme} />
|
||||
<List.SubHeader theme={theme}>Display</List.SubHeader>
|
||||
<SwitchSetting
|
||||
label="Fullscreen"
|
||||
value={fullScreenMode}
|
||||
onPress={() =>
|
||||
dispatch(setAppSettings('fullScreenMode', !fullScreenMode))
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<SwitchSetting
|
||||
label="Show progress percentage"
|
||||
value={showScrollPercentage}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
setAppSettings('showScrollPercentage', !showScrollPercentage),
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
|
||||
<SwitchSetting
|
||||
label="Show battery and time"
|
||||
value={showBatteryAndTime}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
setAppSettings('showBatteryAndTime', !showBatteryAndTime),
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<List.Divider theme={theme} />
|
||||
|
||||
<List.SubHeader theme={theme}>Reader</List.SubHeader>
|
||||
<View style={styles.pressableListItem}>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
Themes
|
||||
</Text>
|
||||
<ScrollView
|
||||
contentContainerStyle={{
|
||||
flexDirection: 'column-reverse',
|
||||
alignItems: 'flex-end',
|
||||
}}
|
||||
style={{ marginLeft: 16 }}
|
||||
horizontal={true}
|
||||
showsHorizontalScrollIndicator={false}
|
||||
>
|
||||
<Row>
|
||||
{readerThemes.map((item, index) => (
|
||||
<ToggleColorButton
|
||||
key={index}
|
||||
selected={
|
||||
reader.theme === item.backgroundColor &&
|
||||
reader.textColor === item.textColor
|
||||
}
|
||||
backgroundColor={item.backgroundColor}
|
||||
textColor={item.textColor}
|
||||
onPress={() => {
|
||||
dispatch(
|
||||
setReaderSettings('theme', item.backgroundColor),
|
||||
);
|
||||
dispatch(setReaderSettings('textColor', item.textColor));
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Row>
|
||||
</ScrollView>
|
||||
</View>
|
||||
<List.ColorItem
|
||||
title="Background Color"
|
||||
description={readerBackground(reader.theme).toUpperCase()}
|
||||
onPress={readerBackgroundModal.showModal}
|
||||
theme={theme}
|
||||
/>
|
||||
<List.ColorItem
|
||||
title="Text Color"
|
||||
description={
|
||||
reader.textColor.toUpperCase() || readerTextColor(reader.theme)
|
||||
}
|
||||
onPress={readerTextColorModal.showModal}
|
||||
theme={theme}
|
||||
/>
|
||||
{!readerThemes.some(
|
||||
item =>
|
||||
item.backgroundColor === reader.theme &&
|
||||
item.textColor === reader.textColor,
|
||||
) ? (
|
||||
<Button
|
||||
style={{ margin: 16 }}
|
||||
va
|
||||
theme={theme}
|
||||
title="Save Custom Theme"
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
saveCustomReaderTheme({
|
||||
theme: {
|
||||
backgroundColor: reader.theme,
|
||||
textColor: reader.textColor,
|
||||
},
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
{customThemes.some(
|
||||
item =>
|
||||
item.backgroundColor === reader.theme &&
|
||||
item.textColor === reader.textColor,
|
||||
) ? (
|
||||
<Button
|
||||
style={{ margin: 16 }}
|
||||
va
|
||||
theme={theme}
|
||||
title="Delete Custom Theme"
|
||||
variation={ButtonVariation.CLEAR}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
deleteCustomReaderTheme({
|
||||
theme: {
|
||||
backgroundColor: reader.theme,
|
||||
textColor: reader.textColor,
|
||||
},
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
<Pressable style={styles.pressableListItem}>
|
||||
<View>
|
||||
<Text style={{ color: theme.textColorPrimary, fontSize: 16 }}>
|
||||
Text Align
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorSecondary,
|
||||
textTransform: 'capitalize',
|
||||
}}
|
||||
>
|
||||
{reader.textAlign}
|
||||
</Text>
|
||||
</View>
|
||||
<Row>
|
||||
{textAlignments.map(item => (
|
||||
<ToggleButton
|
||||
key={item.value}
|
||||
icon={item.icon}
|
||||
onPress={() => {
|
||||
dispatch(setReaderSettings('textAlign', item.value));
|
||||
}}
|
||||
selected={item.value === reader.textAlign}
|
||||
theme={theme}
|
||||
/>
|
||||
))}
|
||||
</Row>
|
||||
</Pressable>
|
||||
<List.Item
|
||||
title="Font"
|
||||
description={
|
||||
fonts.find(item => item.fontFamily === reader.fontFamily)?.name
|
||||
}
|
||||
onPress={readerFontPickerModal.showModal}
|
||||
theme={theme}
|
||||
/>
|
||||
<Row
|
||||
style={{
|
||||
justifyContent: 'space-between',
|
||||
marginHorizontal: 16,
|
||||
marginVertical: 8,
|
||||
}}
|
||||
>
|
||||
<Text style={{ color: theme.textColorPrimary, fontSize: 16 }}>
|
||||
Font size
|
||||
</Text>
|
||||
<Row>
|
||||
<IconButton
|
||||
icon="minus"
|
||||
color={theme.colorAccent}
|
||||
size={26}
|
||||
disabled={reader.textSize <= 1 ? true : false}
|
||||
onPress={() =>
|
||||
dispatch(setReaderSettings('textSize', reader.textSize - 1))
|
||||
}
|
||||
style={{ marginVertical: 0 }}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
paddingHorizontal: 24,
|
||||
}}
|
||||
>
|
||||
{reader.textSize}
|
||||
</Text>
|
||||
<IconButton
|
||||
icon="plus"
|
||||
color={theme.colorAccent}
|
||||
size={26}
|
||||
onPress={() =>
|
||||
dispatch(setReaderSettings('textSize', reader.textSize + 1))
|
||||
}
|
||||
style={{ marginVertical: 0 }}
|
||||
/>
|
||||
</Row>
|
||||
</Row>
|
||||
<Row
|
||||
style={{
|
||||
justifyContent: 'space-between',
|
||||
marginHorizontal: 16,
|
||||
marginVertical: 8,
|
||||
}}
|
||||
>
|
||||
<Text style={{ color: theme.textColorPrimary, fontSize: 16 }}>
|
||||
Padding
|
||||
</Text>
|
||||
<Row>
|
||||
<IconButton
|
||||
icon="minus"
|
||||
color={theme.colorAccent}
|
||||
size={26}
|
||||
disabled={reader.padding <= 0 ? true : false}
|
||||
onPress={() =>
|
||||
dispatch(setReaderSettings('padding', reader.padding - 1))
|
||||
}
|
||||
style={{ marginVertical: 0 }}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
paddingHorizontal: 24,
|
||||
}}
|
||||
>
|
||||
{`${reader.padding}%`}
|
||||
</Text>
|
||||
<IconButton
|
||||
icon="plus"
|
||||
color={theme.colorAccent}
|
||||
size={26}
|
||||
disabled={reader.padding >= 10 ? true : false}
|
||||
onPress={() =>
|
||||
dispatch(setReaderSettings('padding', reader.padding + 1))
|
||||
}
|
||||
style={{ marginVertical: 0 }}
|
||||
/>
|
||||
</Row>
|
||||
</Row>
|
||||
<Row
|
||||
style={{
|
||||
justifyContent: 'space-between',
|
||||
marginHorizontal: 16,
|
||||
marginVertical: 8,
|
||||
}}
|
||||
>
|
||||
<Text style={{ color: theme.textColorPrimary, fontSize: 16 }}>
|
||||
Line height
|
||||
</Text>
|
||||
<Row>
|
||||
<IconButton
|
||||
icon="minus"
|
||||
color={theme.colorAccent}
|
||||
size={26}
|
||||
disabled={reader.lineHeight <= 1.3 ? true : false}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
setReaderSettings('lineHeight', reader.lineHeight - 0.1),
|
||||
)
|
||||
}
|
||||
style={{ marginVertical: 0 }}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
color: theme.textColorPrimary,
|
||||
paddingHorizontal: 24,
|
||||
}}
|
||||
>
|
||||
{`${Math.round(reader.lineHeight * 10) / 10}%`}
|
||||
</Text>
|
||||
<IconButton
|
||||
icon="plus"
|
||||
color={theme.colorAccent}
|
||||
size={26}
|
||||
disabled={reader.lineHeight >= 2 ? true : false}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
setReaderSettings('lineHeight', reader.lineHeight + 0.1),
|
||||
)
|
||||
}
|
||||
style={{ marginVertical: 0 }}
|
||||
/>
|
||||
</Row>
|
||||
</Row>
|
||||
{useWebViewForChapter ? (
|
||||
<>
|
||||
<List.Divider theme={theme} />
|
||||
<List.SubHeader theme={theme}>Custom CSS</List.SubHeader>
|
||||
<View style={{ paddingHorizontal: 16, paddingBottom: 8 }}>
|
||||
<TextInput
|
||||
style={{ color: theme.textColorPrimary, fontSize: 16 }}
|
||||
value={customCSS}
|
||||
onChangeText={text => setcustomCSS(text)}
|
||||
placeholderTextColor={theme.textColorSecondary}
|
||||
placeholder="Example: body { color: red; }"
|
||||
multiline={true}
|
||||
/>
|
||||
<View style={{ flexDirection: 'row-reverse' }}>
|
||||
<Button
|
||||
theme={theme}
|
||||
onPress={() =>
|
||||
dispatch(setReaderSettings('customCSS', customCSS))
|
||||
}
|
||||
style={{ marginLeft: 8 }}
|
||||
title="Save"
|
||||
variation={ButtonVariation.CLEAR}
|
||||
/>
|
||||
<Button
|
||||
theme={theme}
|
||||
onPress={() => {
|
||||
setcustomCSS('');
|
||||
dispatch(setReaderSettings('customCSS', ''));
|
||||
}}
|
||||
title="Clear"
|
||||
variation={ButtonVariation.CLEAR}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
) : null}
|
||||
</ScrollView>
|
||||
</KeyboardAvoidingView>
|
||||
|
||||
<ColorPickerModal
|
||||
title="Reader background color"
|
||||
modalVisible={readerBackgroundModal.visible}
|
||||
color={readerBackground(reader.theme)}
|
||||
hideModal={readerBackgroundModal.hideModal}
|
||||
theme={theme}
|
||||
onSubmit={setReaderBackground}
|
||||
/>
|
||||
<ColorPickerModal
|
||||
title="Reader text color"
|
||||
modalVisible={readerTextColorModal.visible}
|
||||
color={reader.textColor}
|
||||
hideModal={readerTextColorModal.hideModal}
|
||||
theme={theme}
|
||||
onSubmit={setReaderTextColor}
|
||||
/>
|
||||
<FontPickerModal
|
||||
currentFont={reader.fontFamily}
|
||||
visible={readerFontPickerModal.visible}
|
||||
hideModal={readerFontPickerModal.hideModal}
|
||||
theme={theme}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsReaderScreen;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
pressableListItem: {
|
||||
padding: 16,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
fontContainer: {
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
marginHorizontal: 6,
|
||||
},
|
||||
fontContent: {
|
||||
borderRadius: 8,
|
||||
paddingHorizontal: 10,
|
||||
paddingVertical: 4,
|
||||
},
|
||||
});
|
||||
+1
-1
@@ -8,7 +8,7 @@ import { ScreenContainer } from '../../components/Common';
|
||||
import { List } from '../../components/List';
|
||||
import { ThemePicker } from '../../components/ThemePicker/ThemePicker';
|
||||
import SwitchSetting from '../../components/Switch/Switch';
|
||||
import ColorPickerModal from '../../components/ColorPickerModal';
|
||||
import ColorPickerModal from '../../components/ColorPickerModal/ColorPickerModal';
|
||||
|
||||
import { useSettings, useTheme } from '../../hooks/reduxHooks';
|
||||
import {
|
||||
+17
-8
@@ -3,29 +3,38 @@ import { StyleSheet } from 'react-native';
|
||||
|
||||
import { Portal, Modal } from 'react-native-paper';
|
||||
|
||||
import { RadioButton } from '../../../components/RadioButton/RadioButton';
|
||||
import { RadioButton } from '@components/RadioButton/RadioButton';
|
||||
|
||||
import { useAppDispatch, useTheme } from '@redux/hooks';
|
||||
import { setReaderSettings } from '../../../redux/settings/settings.actions';
|
||||
import { fonts } from '../../../services/utils/constants';
|
||||
|
||||
const FontPickerModal = ({
|
||||
theme,
|
||||
dispatch,
|
||||
import { readerFonts } from '../../../utils/constants/readerConstants';
|
||||
|
||||
interface FontPickerModalProps {
|
||||
visible: boolean;
|
||||
onDismiss: () => void;
|
||||
currentFont: string;
|
||||
}
|
||||
|
||||
const FontPickerModal: React.FC<FontPickerModalProps> = ({
|
||||
currentFont,
|
||||
hideModal,
|
||||
onDismiss,
|
||||
visible,
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return (
|
||||
<Portal>
|
||||
<Modal
|
||||
visible={visible}
|
||||
onDismiss={hideModal}
|
||||
onDismiss={onDismiss}
|
||||
contentContainerStyle={[
|
||||
styles.containerStyle,
|
||||
{ backgroundColor: theme.colorPrimaryDark },
|
||||
]}
|
||||
>
|
||||
{fonts.map(item => (
|
||||
{readerFonts.map(item => (
|
||||
<RadioButton
|
||||
key={item.fontFamily}
|
||||
status={currentFont === item.fontFamily}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { StyleSheet, Text, TextStyle, View } from 'react-native';
|
||||
import React from 'react';
|
||||
|
||||
import { useAppDispatch, useReaderSettings, useTheme } from '@redux/hooks';
|
||||
import { IconButtonV2 } from '@components/index';
|
||||
import { setReaderSettings } from '@redux/settings/settings.actions';
|
||||
import { getString } from '@strings/translations';
|
||||
|
||||
interface ReaderTextSizeProps {
|
||||
labelStyle?: TextStyle | TextStyle[];
|
||||
}
|
||||
|
||||
const ReaderTextSize: React.FC<ReaderTextSizeProps> = ({ labelStyle }) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { textSize } = useReaderSettings();
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={[{ color: theme.textColorSecondary }, labelStyle]}>
|
||||
{getString('readerScreen.bottomSheet.textSize')}
|
||||
</Text>
|
||||
<View style={styles.buttonContainer}>
|
||||
<IconButtonV2
|
||||
name="minus"
|
||||
color={theme.colorAccent}
|
||||
size={26}
|
||||
disabled={textSize <= 0}
|
||||
onPress={() => dispatch(setReaderSettings('textSize', textSize - 1))}
|
||||
theme={theme}
|
||||
/>
|
||||
<Text style={[styles.value, { color: theme.textColorPrimary }]}>
|
||||
{textSize}
|
||||
</Text>
|
||||
<IconButtonV2
|
||||
name="plus"
|
||||
color={theme.colorAccent}
|
||||
size={26}
|
||||
onPress={() => dispatch(setReaderSettings('textSize', textSize + 1))}
|
||||
theme={theme}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReaderTextSize;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: 16,
|
||||
marginVertical: 6,
|
||||
},
|
||||
value: {
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
buttonContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,514 @@
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TextStyle,
|
||||
View,
|
||||
ViewStyle,
|
||||
ScrollView,
|
||||
useWindowDimensions,
|
||||
} from 'react-native';
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { defaultTo } from 'lodash';
|
||||
import WebView from 'react-native-webview';
|
||||
import { Portal } from 'react-native-paper';
|
||||
|
||||
import {
|
||||
Appbar,
|
||||
Button,
|
||||
ColorPreferenceItem,
|
||||
List,
|
||||
SwitchItem,
|
||||
} from '@components/index';
|
||||
import ReaderThemeSelector from '../../../screens/reader/components/ReaderBottomSheet/ReaderThemeSelector';
|
||||
import ReaderTextAlignSelector from '../../../screens/reader/components/ReaderBottomSheet/ReaderTextAlignSelector';
|
||||
import ColorPickerModal from '@components/ColorPickerModal/ColorPickerModal';
|
||||
import { ButtonVariation } from '@components/Button/Button';
|
||||
import FontPickerModal from './FontPickerModal';
|
||||
import ReaderLineHeight from '../../../screens/reader/components/ReaderBottomSheet/ReaderLineHeight';
|
||||
import ReaderTextSize from './ReaderTextSize';
|
||||
|
||||
import {
|
||||
useTheme,
|
||||
useReaderSettings,
|
||||
useSettingsV1,
|
||||
useAppDispatch,
|
||||
useSettingsV2,
|
||||
} from '@redux/hooks';
|
||||
import { getString } from '@strings/translations';
|
||||
import {
|
||||
setAppSettings,
|
||||
setReaderSettings,
|
||||
} from '@redux/settings/settings.actions';
|
||||
|
||||
import { dummyHTML, dummyText } from './utils';
|
||||
import useBoolean from '@hooks/useBoolean';
|
||||
import {
|
||||
deleteCustomReaderTheme,
|
||||
saveCustomReaderTheme,
|
||||
} from '@redux/settings/settingsSlice';
|
||||
import {
|
||||
presetReaderThemes,
|
||||
readerFonts,
|
||||
} from '../../../utils/constants/readerConstants';
|
||||
|
||||
const READER_HEIGHT = 400;
|
||||
|
||||
type TextAlignments =
|
||||
| 'left'
|
||||
| 'center'
|
||||
| 'auto'
|
||||
| 'right'
|
||||
| 'justify'
|
||||
| undefined;
|
||||
|
||||
const SettingsReaderScreen = () => {
|
||||
const theme = useTheme();
|
||||
const navigation = useNavigation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const readerSettings = useReaderSettings();
|
||||
const {
|
||||
useWebViewForChapter = false,
|
||||
verticalSeekbar = true,
|
||||
swipeGestures = false,
|
||||
autoScroll = false,
|
||||
autoScrollInterval = 10,
|
||||
autoScrollOffset = null,
|
||||
fullScreenMode = true,
|
||||
showScrollPercentage = true,
|
||||
showBatteryAndTime = false,
|
||||
} = useSettingsV1();
|
||||
|
||||
const {
|
||||
reader: { customThemes = [] },
|
||||
} = useSettingsV2();
|
||||
|
||||
const webViewCSS = `
|
||||
<style>
|
||||
body {
|
||||
color: ${readerSettings.textColor};
|
||||
text-align: ${readerSettings.textAlign};
|
||||
line-height: ${readerSettings.lineHeight};
|
||||
font-size: ${readerSettings.textSize}px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
padding-left: ${readerSettings.padding}%;
|
||||
padding-right: ${readerSettings.padding}%;
|
||||
font-family: ${readerSettings.fontFamily};
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
${readerSettings.customCSS}
|
||||
@font-face {
|
||||
font-family: ${readerSettings.fontFamily};
|
||||
src: url("file:///android_asset/fonts/${readerSettings.fontFamily}.ttf");
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
const readerBackgroundColor = readerSettings.theme;
|
||||
|
||||
const textReaderContainerStyle: ViewStyle = {
|
||||
padding: `${readerSettings.padding}%`,
|
||||
backgroundColor: readerBackgroundColor,
|
||||
height: READER_HEIGHT,
|
||||
};
|
||||
|
||||
const textReaderStyle: TextStyle = {
|
||||
fontFamily: readerSettings.fontFamily,
|
||||
fontSize: readerSettings.textSize,
|
||||
textAlign: readerSettings.textAlign as TextAlignments,
|
||||
lineHeight: readerSettings.textSize * readerSettings.lineHeight,
|
||||
color: readerSettings.textColor,
|
||||
};
|
||||
|
||||
const readerBackgroundModal = useBoolean();
|
||||
const readerTextColorModal = useBoolean();
|
||||
const readerFontPickerModal = useBoolean();
|
||||
|
||||
const isCurrentThemeCustom = customThemes.some(
|
||||
item =>
|
||||
item.backgroundColor === readerSettings.theme &&
|
||||
item.textColor === readerSettings.textColor,
|
||||
);
|
||||
|
||||
const isCurrentThemePreset = presetReaderThemes.some(
|
||||
item =>
|
||||
item.backgroundColor === readerSettings.theme &&
|
||||
item.textColor === readerSettings.textColor,
|
||||
);
|
||||
|
||||
const currentFontName = readerFonts.find(
|
||||
item => item.fontFamily === readerSettings.fontFamily,
|
||||
)?.name;
|
||||
|
||||
const areAutoScrollSettingsDefault =
|
||||
autoScrollInterval === 10 && autoScrollOffset === null;
|
||||
|
||||
const [customCSS, setcustomCSS] = useState(readerSettings.customCSS);
|
||||
|
||||
const { height: screenHeight } = useWindowDimensions();
|
||||
|
||||
const labelStyle = [styles.fontSizeL, { color: theme.textColorPrimary }];
|
||||
|
||||
return (
|
||||
<>
|
||||
<Appbar
|
||||
title={getString('moreScreen.settingsScreen.readerSettings.title')}
|
||||
handleGoBack={navigation.goBack}
|
||||
theme={theme}
|
||||
/>
|
||||
<ScrollView
|
||||
style={styles.flex}
|
||||
contentContainerStyle={styles.bottomInset}
|
||||
>
|
||||
{useWebViewForChapter ? (
|
||||
<WebView
|
||||
originWhitelist={['*']}
|
||||
style={{
|
||||
height: READER_HEIGHT,
|
||||
backgroundColor: readerBackgroundColor,
|
||||
}}
|
||||
nestedScrollEnabled={true}
|
||||
m
|
||||
source={{
|
||||
html: `
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
|
||||
${webViewCSS}
|
||||
</head>
|
||||
<body>
|
||||
${dummyHTML}
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<View style={textReaderContainerStyle}>
|
||||
<Text style={textReaderStyle}>{dummyText}</Text>
|
||||
</View>
|
||||
)}
|
||||
<SwitchItem
|
||||
label={getString('readerScreen.bottomSheet.renderHml')}
|
||||
value={useWebViewForChapter}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
setAppSettings('useWebViewForChapter', !useWebViewForChapter),
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<SwitchItem
|
||||
label={getString('readerScreen.bottomSheet.verticalSeekbar')}
|
||||
description={getString(
|
||||
'moreScreen.settingsScreen.readerSettings.verticalSeekbarDesc',
|
||||
)}
|
||||
value={verticalSeekbar}
|
||||
onPress={() =>
|
||||
dispatch(setAppSettings('verticalSeekbar', !verticalSeekbar))
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<SwitchItem
|
||||
label={getString('readerScreen.bottomSheet.swipeGestures')}
|
||||
value={swipeGestures}
|
||||
onPress={() =>
|
||||
dispatch(setAppSettings('swipeGestures', !swipeGestures))
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
{!useWebViewForChapter ? (
|
||||
<SwitchItem
|
||||
label={getString('readerScreen.bottomSheet.autoscroll')}
|
||||
value={autoScroll}
|
||||
onPress={() => dispatch(setAppSettings('autoScroll', !autoScroll))}
|
||||
theme={theme}
|
||||
/>
|
||||
) : null}
|
||||
{useWebViewForChapter ? (
|
||||
<>
|
||||
<List.Divider theme={theme} />
|
||||
<List.SubHeader theme={theme}>
|
||||
{getString('moreScreen.settingsScreen.readerSettings.customCSS')}
|
||||
</List.SubHeader>
|
||||
<View style={styles.customCSSContainer}>
|
||||
<TextInput
|
||||
style={[{ color: theme.textColorPrimary }, styles.fontSizeL]}
|
||||
value={customCSS}
|
||||
onChangeText={text => setcustomCSS(text)}
|
||||
placeholderTextColor={theme.textColorSecondary}
|
||||
placeholder="Example: body { color: red; }"
|
||||
multiline={true}
|
||||
/>
|
||||
<View style={styles.customCSSButtons}>
|
||||
<Button
|
||||
theme={theme}
|
||||
onPress={() =>
|
||||
dispatch(setReaderSettings('customCSS', customCSS))
|
||||
}
|
||||
style={styles.marginLeftS}
|
||||
title={getString('common.save')}
|
||||
variation={ButtonVariation.OUTLINED}
|
||||
/>
|
||||
<Button
|
||||
theme={theme}
|
||||
onPress={() => {
|
||||
setcustomCSS('');
|
||||
dispatch(setReaderSettings('customCSS', ''));
|
||||
}}
|
||||
title={getString('common.clear')}
|
||||
variation={ButtonVariation.OUTLINED}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
) : autoScroll ? (
|
||||
<>
|
||||
<List.Divider theme={theme} />
|
||||
<List.SubHeader theme={theme}>
|
||||
{getString('readerScreen.bottomSheet.autoscroll')}
|
||||
</List.SubHeader>
|
||||
<View style={styles.autoScrollInterval}>
|
||||
<Text
|
||||
style={[labelStyle, styles.paddingRightM]}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{getString(
|
||||
'moreScreen.settingsScreen.readerSettings.autoScrollInterval',
|
||||
)}
|
||||
</Text>
|
||||
<TextInput
|
||||
style={labelStyle}
|
||||
defaultValue={defaultTo(autoScrollInterval, 10).toString()}
|
||||
keyboardType="numeric"
|
||||
onChangeText={text => {
|
||||
if (text) {
|
||||
dispatch(
|
||||
setAppSettings('autoScrollInterval', Number(text)),
|
||||
);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.autoScrollInterval}>
|
||||
<Text
|
||||
style={[labelStyle, styles.paddingRightM]}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{getString(
|
||||
'moreScreen.settingsScreen.readerSettings.autoScrollOffset',
|
||||
)}
|
||||
</Text>
|
||||
<TextInput
|
||||
style={labelStyle}
|
||||
defaultValue={defaultTo(
|
||||
autoScrollOffset,
|
||||
Math.round(screenHeight),
|
||||
).toString()}
|
||||
keyboardType="numeric"
|
||||
onChangeText={text => {
|
||||
if (text) {
|
||||
dispatch(setAppSettings('autoScrollOffset', Number(text)));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
{!areAutoScrollSettingsDefault ? (
|
||||
<View style={styles.customCSSButtons}>
|
||||
<Button
|
||||
style={styles.customThemeButton}
|
||||
theme={theme}
|
||||
title={getString('common.reset')}
|
||||
variation={ButtonVariation.OUTLINED}
|
||||
onPress={() => {
|
||||
dispatch(setAppSettings('autoScrollInterval', 10));
|
||||
dispatch(setAppSettings('autoScrollOffset', null));
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
|
||||
<List.Divider theme={theme} />
|
||||
<List.SubHeader theme={theme}>
|
||||
{getString('novelScreen.bottomSheet.display')}
|
||||
</List.SubHeader>
|
||||
<SwitchItem
|
||||
label={getString('readerScreen.bottomSheet.fullscreen')}
|
||||
value={fullScreenMode}
|
||||
onPress={() =>
|
||||
dispatch(setAppSettings('fullScreenMode', !fullScreenMode))
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<SwitchItem
|
||||
label={getString('readerScreen.bottomSheet.showProgressPercentage')}
|
||||
value={showScrollPercentage}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
setAppSettings('showScrollPercentage', !showScrollPercentage),
|
||||
)
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<SwitchItem
|
||||
label={getString('readerScreen.bottomSheet.showBatteryAndTime')}
|
||||
value={showBatteryAndTime}
|
||||
onPress={() =>
|
||||
dispatch(setAppSettings('showBatteryAndTime', !showBatteryAndTime))
|
||||
}
|
||||
theme={theme}
|
||||
/>
|
||||
<List.Divider theme={theme} />
|
||||
<List.SubHeader theme={theme}>
|
||||
{getString('moreScreen.settingsScreen.readerSettings.readerTheme')}
|
||||
</List.SubHeader>
|
||||
<ReaderThemeSelector
|
||||
label={getString('moreScreen.settingsScreen.readerSettings.preset')}
|
||||
labelStyle={labelStyle}
|
||||
/>
|
||||
<ColorPreferenceItem
|
||||
label={getString(
|
||||
'moreScreen.settingsScreen.readerSettings.backgroundColor',
|
||||
)}
|
||||
description={readerSettings.theme}
|
||||
onPress={readerBackgroundModal.setTrue}
|
||||
theme={theme}
|
||||
/>
|
||||
<ColorPreferenceItem
|
||||
label={getString(
|
||||
'moreScreen.settingsScreen.readerSettings.textColor',
|
||||
)}
|
||||
description={readerSettings.textColor}
|
||||
onPress={readerTextColorModal.setTrue}
|
||||
theme={theme}
|
||||
/>
|
||||
{isCurrentThemeCustom ? (
|
||||
<View style={styles.customCSSButtons}>
|
||||
<Button
|
||||
style={styles.customThemeButton}
|
||||
theme={theme}
|
||||
title={getString(
|
||||
'moreScreen.settingsScreen.readerSettings.deleteCustomTheme',
|
||||
)}
|
||||
variation={ButtonVariation.OUTLINED}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
deleteCustomReaderTheme({
|
||||
theme: {
|
||||
backgroundColor: readerSettings.theme,
|
||||
textColor: readerSettings.textColor,
|
||||
},
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
) : !isCurrentThemePreset ? (
|
||||
<View style={styles.customCSSButtons}>
|
||||
<Button
|
||||
style={styles.customThemeButton}
|
||||
theme={theme}
|
||||
title={getString(
|
||||
'moreScreen.settingsScreen.readerSettings.saveCustomTheme',
|
||||
)}
|
||||
variation={ButtonVariation.OUTLINED}
|
||||
onPress={() =>
|
||||
dispatch(
|
||||
saveCustomReaderTheme({
|
||||
theme: {
|
||||
backgroundColor: readerSettings.theme,
|
||||
textColor: readerSettings.textColor,
|
||||
},
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
) : null}
|
||||
<ReaderTextAlignSelector labelStyle={labelStyle} />
|
||||
<ReaderTextSize labelStyle={labelStyle} />
|
||||
<ReaderLineHeight labelStyle={labelStyle} />
|
||||
<List.Item
|
||||
title={getString('readerScreen.bottomSheet.fontStyle')}
|
||||
description={currentFontName}
|
||||
onPress={readerFontPickerModal.setTrue}
|
||||
theme={theme}
|
||||
/>
|
||||
</ScrollView>
|
||||
<Portal>
|
||||
<ColorPickerModal
|
||||
title={getString(
|
||||
'moreScreen.settingsScreen.readerSettings.backgroundColor',
|
||||
)}
|
||||
visible={readerBackgroundModal.value}
|
||||
color={readerSettings.theme}
|
||||
closeModal={readerBackgroundModal.setFalse}
|
||||
theme={theme}
|
||||
onSubmit={color => dispatch(setReaderSettings('theme', color))}
|
||||
/>
|
||||
<ColorPickerModal
|
||||
title={getString(
|
||||
'moreScreen.settingsScreen.readerSettings.textColor',
|
||||
)}
|
||||
visible={readerTextColorModal.value}
|
||||
color={readerSettings.textColor}
|
||||
closeModal={readerTextColorModal.setFalse}
|
||||
theme={theme}
|
||||
onSubmit={color => dispatch(setReaderSettings('textColor', color))}
|
||||
/>
|
||||
<FontPickerModal
|
||||
currentFont={readerSettings.fontFamily}
|
||||
visible={readerFontPickerModal.value}
|
||||
onDismiss={readerFontPickerModal.setFalse}
|
||||
/>
|
||||
</Portal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SettingsReaderScreen;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
flex: {
|
||||
flex: 1,
|
||||
},
|
||||
bottomInset: {
|
||||
paddingBottom: 40,
|
||||
},
|
||||
fontSizeL: {
|
||||
fontSize: 16,
|
||||
},
|
||||
autoScrollInterval: {
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 8,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
customThemeButton: {
|
||||
marginHorizontal: 16,
|
||||
marginBottom: 16,
|
||||
},
|
||||
customCSSContainer: {
|
||||
paddingHorizontal: 16,
|
||||
paddingBottom: 8,
|
||||
},
|
||||
marginLeftS: {
|
||||
marginLeft: 8,
|
||||
},
|
||||
customCSSButtons: {
|
||||
flex: 1,
|
||||
flexDirection: 'row-reverse',
|
||||
},
|
||||
paddingRightM: {
|
||||
flex: 1,
|
||||
paddingRight: 16,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
export const dummyHTML = `
|
||||
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean lobortis, diam sed malesuada bibendum, nulla libero scelerisque sapien, nec interdum nisl ipsum ac ipsum. In lacinia eros ut quam commodo, in finibus augue ultricies. Vestibulum ex purus, condimentum eget sem at, molestie semper mi. Mauris ac feugiat quam. Pellentesque sagittis bibendum nibh eu lacinia. Aenean rhoncus, velit sit amet mollis egestas, diam turpis ornare velit, a dictum elit velit in erat. Quisque luctus in sem a vulputate.
|
||||
</p>
|
||||
<p> Pellentesque id tempus orci, non finibus tortor. Suspendisse in neque non eros eleifend hendrerit vitae a lacus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Nunc interdum magna nulla, eget pharetra arcu dapibus eu. Pellentesque sed lectus sit amet sem porta lacinia. Curabitur consectetur dolor in nibh varius, ac placerat erat pellentesque. Proin in justo condimentum, fermentum lacus eget, ultrices ante. Fusce tempor blandit erat nec mollis. Vivamus in leo et nunc consectetur elementum nec ac lectus.
|
||||
</p>
|
||||
<p> In consectetur libero tempor metus interdum, sit amet viverra leo dapibus. Nullam tincidunt justo hendrerit lorem maximus, eu pretium erat fringilla. Nulla scelerisque leo at enim convallis, a elementum velit laoreet. Aliquam quis vestibulum quam. Morbi ut sollicitudin mi, et laoreet elit. Vivamus mattis, nulla at blandit sodales, lectus lacus luctus metus, non euismod neque urna vel nisl. Quisque vitae ante vitae orci tempus egestas quis eu nibh. Phasellus eget nulla non velit tincidunt fringilla eget nec libero. Morbi tempor erat quis rutrum condimentum.
|
||||
</p>
|
||||
<p> Cras sem magna, tempus sed urna eget, scelerisque tincidunt tortor. Cras euismod turpis libero, ut condimentum nulla ultrices id. Phasellus faucibus, elit ut imperdiet euismod, enim dui volutpat turpis, in tincidunt ex ligula non felis. Praesent erat erat, ultrices ut imperdiet sed, congue eu leo. Aliquam viverra fringilla ultrices. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent ac malesuada massa. Cras eu augue in dui venenatis laoreet sit amet eget sem. Nullam malesuada sapien felis, et varius neque auctor eu.
|
||||
</p>
|
||||
<p> Sed vestibulum facilisis libero, in aliquet mauris lobortis et. In vitae lectus id risus cursus dictum at ac mi. Praesent ac lectus eget nunc elementum pellentesque. Ut at dui magna. Aliquam mattis posuere gravida. Morbi volutpat, dolor quis varius tincidunt, quam nulla vulputate libero, eu sagittis dui odio et magna. Sed luctus lectus ante, sit amet ultrices ligula convallis vitae. Sed efficitur libero nec quam porta, et fringilla turpis egestas. Nulla facilisi. Duis leo tellus, porta non enim eu, tincidunt cursus lorem.
|
||||
</p>
|
||||
`;
|
||||
|
||||
export const dummyText =
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean lobortis, diam sed malesuada bibendum, nulla libero scelerisque sapien, nec interdum nisl ipsum ac ipsum. In lacinia eros ut quam commodo, in finibus augue ultricies. Vestibulum ex purus, condimentum eget sem at, molestie semper mi. Mauris ac feugiat quam. Pellentesque sagittis bibendum nibh eu lacinia. Aenean rhoncus, velit sit amet mollis egestas, diam turpis ornare velit, a dictum elit velit in erat. Quisque luctus in sem a vulputate.\n\nPellentesque id tempus orci, non finibus tortor. Suspendisse in neque non eros eleifend hendrerit vitae a lacus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae;';
|
||||
@@ -30,7 +30,7 @@ const SettingsScreen = ({ navigation }) => {
|
||||
theme={theme}
|
||||
/>
|
||||
<List.Item
|
||||
title={getString('moreScreen.settingsScreen.readerSettings')}
|
||||
title={getString('moreScreen.settingsScreen.readerSettings.title')}
|
||||
icon="book-open-outline"
|
||||
onPress={() =>
|
||||
navigation.navigate('SettingsStack', {
|
||||
@@ -1,10 +0,0 @@
|
||||
export const presetReaderThemes = [
|
||||
{ backgroundColor: '#f5f5fa', textColor: '#111111' },
|
||||
{ backgroundColor: '#F7DFC6', textColor: '#593100' },
|
||||
{ backgroundColor: '#dce5e2', textColor: '#000000' },
|
||||
{ backgroundColor: '#292832', textColor: '#CCCCCC' },
|
||||
{
|
||||
backgroundColor: '#000000',
|
||||
textColor: 'rgba(255,255,255,0.7)',
|
||||
},
|
||||
];
|
||||
@@ -7,7 +7,7 @@ export const presetReaderThemes: ReaderTheme[] = [
|
||||
{ backgroundColor: '#292832', textColor: '#CCCCCC' },
|
||||
{
|
||||
backgroundColor: '#000000',
|
||||
textColor: 'rgba(255,255,255,0.7)',
|
||||
textColor: '#FFFFFFB3',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
{
|
||||
"common": {
|
||||
"cancel": "Cancel",
|
||||
"ok": "Ok"
|
||||
"ok": "Ok",
|
||||
"save": "Save",
|
||||
"clear": "Clear",
|
||||
"reset": "Reset"
|
||||
},
|
||||
"library": "Library",
|
||||
"libraryScreen": {
|
||||
@@ -64,7 +67,7 @@
|
||||
"verticalSeekbar": "Vertical Seekbar",
|
||||
"showBatteryAndTime": "Show battery and time",
|
||||
"showProgressPercentage": "Show progress percentage",
|
||||
"swipeGestures": "Swipe left/right to navigate between chapters",
|
||||
"swipeGestures": "Swipe left or right to navigate between chapters",
|
||||
"allowTextSelection": "Allow text selection"
|
||||
}
|
||||
},
|
||||
@@ -86,8 +89,21 @@
|
||||
"settingsScreen": {
|
||||
"generalSettings": "General",
|
||||
"generalSettingsScreen": {},
|
||||
"readerSettings": "Reader",
|
||||
"readerSettingsScreen": {},
|
||||
"readerSettings": {
|
||||
"title": "Reader",
|
||||
"readerTheme": "Reader theme",
|
||||
"preset": "Preset",
|
||||
"backgroundColor": "Background color",
|
||||
"textColor": "Text color",
|
||||
"backgroundColorModal": "Reader background color",
|
||||
"textColorModal": "Reader text color",
|
||||
"verticalSeekbarDesc": "Switch between vertical and horizontal seekbar",
|
||||
"autoScrollInterval": "Auto scroll interval (in seconds)",
|
||||
"autoScrollOffset": "Auto scroll offset (screen height by default)",
|
||||
"saveCustomTheme": "Save custom theme",
|
||||
"deleteCustomTheme": "Delete custom theme",
|
||||
"customCSS": "Custom CSS"
|
||||
},
|
||||
"browseSettings": "Browse Settings",
|
||||
"browseSettingsScreen": {
|
||||
"onlyShowPinnedSources": "Only show pinned sources",
|
||||
|
||||
+16
-1
@@ -5,6 +5,9 @@
|
||||
export interface StringMap {
|
||||
'common.cancel': 'string';
|
||||
'common.ok': 'string';
|
||||
'common.save': 'string';
|
||||
'common.clear': 'string';
|
||||
'common.reset': 'string';
|
||||
'library': 'string';
|
||||
'libraryScreen.searchbar': 'string';
|
||||
'libraryScreen.empty': 'string';
|
||||
@@ -61,7 +64,19 @@ export interface StringMap {
|
||||
'more': 'string';
|
||||
'moreScreen.settings': 'string';
|
||||
'moreScreen.settingsScreen.generalSettings': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.title': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.readerTheme': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.preset': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.backgroundColor': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.textColor': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.backgroundColorModal': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.textColorModal': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.verticalSeekbarDesc': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.autoScrollInterval': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.autoScrollOffset': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.saveCustomTheme': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.deleteCustomTheme': 'string';
|
||||
'moreScreen.settingsScreen.readerSettings.customCSS': 'string';
|
||||
'moreScreen.settingsScreen.browseSettings': 'string';
|
||||
'moreScreen.settingsScreen.browseSettingsScreen.onlyShowPinnedSources': 'string';
|
||||
'moreScreen.settingsScreen.browseSettingsScreen.languages': 'string';
|
||||
|
||||
+2
-1
@@ -17,7 +17,8 @@
|
||||
"@components/*": ["./src/components/*"],
|
||||
"@hooks/*": ["./src/hooks/*"],
|
||||
"@screens/*": ["'./src/screens/*"],
|
||||
"@strings/*": ["./strings/*"]
|
||||
"@strings/*": ["./strings/*"],
|
||||
"@redux/*": ["./src/redux/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/"],
|
||||
|
||||
Reference in New Issue
Block a user