refactor: Reader Settings Screen

This commit is contained in:
Rajarshee Chatterjee
2022-05-08 11:47:22 +05:30
parent 94b2dd51cb
commit 7716ab75de
33 changed files with 813 additions and 705 deletions
+1
View File
@@ -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'],
},
+1 -1
View File
@@ -79,7 +79,7 @@ const styles = StyleSheet.create({
justifyContent: 'center',
alignItems: 'center',
paddingVertical: 8,
paddingHorizontal: 16,
paddingHorizontal: 24,
},
outlined: {
borderWidth: 1,
@@ -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,
},
});
+1 -1
View File
@@ -52,10 +52,10 @@ const styles = StyleSheet.create({
},
labelContainer: {
flex: 1,
justifyContent: 'center',
},
label: {
fontSize: 16,
textAlignVertical: 'center',
},
switch: {
marginLeft: 8,
+1
View File
@@ -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';
+7 -7
View File
@@ -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();
+2 -1
View File
@@ -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,
+2
View File
@@ -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,
)
}
+9 -10
View File
@@ -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',
},
});
-628
View File
@@ -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,
},
});
@@ -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 {
@@ -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', {
-10
View File
@@ -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)',
},
];
+1 -1
View File
@@ -7,7 +7,7 @@ export const presetReaderThemes: ReaderTheme[] = [
{ backgroundColor: '#292832', textColor: '#CCCCCC' },
{
backgroundColor: '#000000',
textColor: 'rgba(255,255,255,0.7)',
textColor: '#FFFFFFB3',
},
];
+20 -4
View File
@@ -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
View File
@@ -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
View File
@@ -17,7 +17,8 @@
"@components/*": ["./src/components/*"],
"@hooks/*": ["./src/hooks/*"],
"@screens/*": ["'./src/screens/*"],
"@strings/*": ["./strings/*"]
"@strings/*": ["./strings/*"],
"@redux/*": ["./src/redux/*"]
}
},
"include": ["src/"],