Skip to content

Commit

Permalink
refactor: Custom CSS/JS Modal (#705)
Browse files Browse the repository at this point in the history
* refactor: Custom CSS/JS Modal

* Close Modal on Selecting a File
  • Loading branch information
rajarsheechatterjee authored Sep 2, 2023
1 parent 929b183 commit 3b2ee3d
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 139 deletions.
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ export { default as ColorPreferenceItem } from './ColorPreferenceItem/ColorPrefe
export { default as LoadingMoreIndicator } from './LoadingMoreIndicator/LoadingMoreIndicator';
export { Checkbox } from './Checkbox/Checkbox';
export { RadioButton } from './RadioButton/RadioButton';
export { default as ConfirmationDialog } from './ConfirmationDialog/ConfirmationDialog';
149 changes: 65 additions & 84 deletions src/screens/settings/SettingsReaderScreen/Modals/CustomFileModal.tsx
Original file line number Diff line number Diff line change
@@ -1,118 +1,101 @@
import React, { useState } from 'react';
import { KeyboardAvoidingView, StyleSheet, Text, View } from 'react-native';
import { StyleSheet, Text, View } from 'react-native';
import { Modal, overlay, TextInput } from 'react-native-paper';
import { Button } from '@components/index';
import { MD3ThemeType } from '@theme/types';
import { getString } from '@strings/translations';
import { useAppDispatch } from '@redux/hooks';
import * as DocumentPicker from 'expo-document-picker';
import { StorageAccessFramework } from 'expo-file-system';
import * as DocumentPicker from 'expo-document-picker';

import { Button } from '@components/index';

import { showToast } from '@hooks/showToast';
import { setReaderSettings } from '@redux/settings/settings.actions';
import { useTheme } from '@hooks/useTheme';
import { getString } from '@strings/translations';

interface CustomCSSModalProps {
interface CustomFileModal {
visible: boolean;
onDismiss: () => void;
customFile: string;
setCustomFile: (val: string) => void;
theme: MD3ThemeType;
defaultValue: string;
onSave: (val: string) => void;
title: string;
type?: string;
openFileButtonLabel?: string;
mimeType: 'text/css' | 'application/javascript';
openFileLabel: string;
placeholder?: string;
description?: string;
}

const CustomFileModal: React.FC<CustomCSSModalProps> = ({
const CustomFileModal: React.FC<CustomFileModal> = ({
onDismiss,
visible,
customFile,
setCustomFile,
theme,
defaultValue,
onSave,
title,
type = 'CSS',
openFileButtonLabel = getString(
'moreScreen.settingsScreen.readerSettings.openCSSFile',
),
placeholder = '',
mimeType,
openFileLabel,
placeholder,
description,
}) => {
const [text, setText] = useState(customFile);
const dispatch = useAppDispatch();
let mimeType: string;
if (type === 'CSS') {
mimeType = 'text/css';
} else {
mimeType = 'application/javascript';
}
const theme = useTheme();
const [text, setText] = useState('');

const openCSS = async () => {
const openDocumentPicker = async () => {
try {
const rawCSS = await DocumentPicker.getDocumentAsync({
const file = await DocumentPicker.getDocumentAsync({
copyToCacheDirectory: false,
type: mimeType,
});
if (rawCSS.type === 'success') {
let css = await StorageAccessFramework.readAsStringAsync(rawCSS.uri);
setText(css);

if (file.type === 'success') {
const content = await StorageAccessFramework.readAsStringAsync(
file.uri,
);

onSave(content.trim());
onDismiss();
}
} catch (error: any) {
showToast(error.message);
}
};
const dismiss = () => {
setCustomFile(text.trim());
onDismiss();
};

return (
<Modal
visible={visible}
onDismiss={dismiss}
onDismiss={onDismiss}
contentContainerStyle={[
styles.modalContainer,
{ backgroundColor: overlay(2, theme.surface) },
]}
>
<KeyboardAvoidingView behavior="padding" keyboardVerticalOffset={180}>
<Text style={[styles.modalTitle, { color: theme.onSurface }]}>
{title}
</Text>
<Text style={[{ color: theme.onSurfaceVariant }]}>
{type === 'CSS'
? getString('moreScreen.settingsScreen.readerSettings.cssHint')
: getString('moreScreen.settingsScreen.readerSettings.jsHint')}
</Text>
<TextInput
theme={{ colors: { ...theme } }}
underlineColor={theme.outline}
value={text}
onChangeText={setText}
mode="outlined"
placeholder={placeholder}
placeholderTextColor={theme.onSurfaceVariant}
multiline
style={[
{ color: theme.onSurface },
styles.fontSizeL,
styles.customCSSContainer,
]}
<Text style={[styles.modalTitle, { color: theme.onSurface }]}>
{title}
</Text>
<Text style={[{ color: theme.onSurfaceVariant }]}>{description}</Text>
<TextInput
multiline
mode="outlined"
defaultValue={defaultValue}
onChangeText={setText}
placeholder={placeholder}
placeholderTextColor={theme.onSurfaceVariant}
underlineColor={theme.outline}
style={[{ color: theme.onSurface }, styles.textInput]}
theme={{ colors: { ...theme } }}
/>
<View style={styles.customCSSButtons}>
<Button
onPress={() => {
onSave(text.trim());
onDismiss();
}}
style={styles.button}
title={getString('common.save')}
mode="contained"
/>
<Button
style={styles.button}
onPress={openDocumentPicker}
title={openFileLabel}
/>
<View style={styles.customCSSButtons}>
<Button
onPress={() => {
dispatch(setReaderSettings(`custom${type}`, text.trim()));
dismiss();
}}
style={styles.button}
title={getString('common.save')}
mode="contained"
/>
<Button
style={styles.button}
onPress={openCSS}
title={openFileButtonLabel}
/>
</View>
</KeyboardAvoidingView>
</View>
</Modal>
);
};
Expand All @@ -125,14 +108,12 @@ const styles = StyleSheet.create({
padding: 24,
borderRadius: 28,
},
fontSizeL: {
fontSize: 16,
},
customCSSContainer: {
textInput: {
height: 220,
borderRadius: 14,
marginTop: 16,
marginBottom: 8,
fontSize: 16,
},
modalTitle: {
fontSize: 24,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,39 +1,35 @@
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
import React, { useState } from 'react';

import { Button, List } from '@components/index';
import { Portal } from 'react-native-paper';

import { setReaderSettings } from '@redux/settings/settings.actions';
import { Button, List, ConfirmationDialog } from '@components/index';

import useBoolean from '@hooks/useBoolean';
import { useTheme } from '@hooks/useTheme';
import { useAppDispatch, useReaderSettings } from '@redux/hooks';
import { setReaderSettings } from '@redux/settings/settings.actions';
import { getString } from '@strings/translations';

import CustomFileModal from '../Modals/CustomFileModal';
import useBoolean from '@hooks/useBoolean';
import { Portal } from 'react-native-paper';

const CustomCSSSettings = () => {
const theme = useTheme();
const readerSettings = useReaderSettings();
const [customCSS, setCustomCSS] = useState(readerSettings.customCSS);
const dispatch = useAppDispatch();

const cssModal = useBoolean();
const clearCSSModal = useBoolean();

return (
<>
<View style={styles.header}>
<List.SubHeader theme={theme}>
{getString('moreScreen.settingsScreen.readerSettings.customCSS')}
</List.SubHeader>
<List.SubHeader theme={theme}>
{readerSettings.customCSS !== customCSS
? getString('moreScreen.settingsScreen.readerSettings.notSaved')
: null}
</List.SubHeader>
</View>
<View style={styles.customCSSContainer}>
<Text numberOfLines={3} style={{ color: theme.onSurface }}>
{customCSS || 'Example: body {margin: 10px;}'}
<Text numberOfLines={3} style={[{ color: theme.onSurface }]}>
{readerSettings.customCSS || 'Example: body {margin: 10px;}'}
</Text>
<View style={styles.customCSSButtons}>
<Button
Expand All @@ -42,28 +38,41 @@ const CustomCSSSettings = () => {
title={getString('common.edit')}
/>
<Button
onPress={() => {
setCustomCSS('');
dispatch(setReaderSettings('customCSS', ''));
}}
onPress={clearCSSModal.setTrue}
title={getString('common.clear')}
/>
</View>
</View>
{/*
Modals
*/}

{/* Modals */}
<Portal>
<CustomFileModal
visible={cssModal.value}
onDismiss={cssModal.setFalse}
defaultValue={readerSettings.customCSS}
mimeType="text/css"
title={getString(
'moreScreen.settingsScreen.readerSettings.customCSS',
)}
visible={cssModal.value}
onDismiss={cssModal.setFalse}
theme={theme}
customFile={customCSS}
setCustomFile={setCustomCSS}
description={getString(
'moreScreen.settingsScreen.readerSettings.cssHint',
)}
placeholder="Example: body {margin: 10px;}"
openFileLabel={getString(
'moreScreen.settingsScreen.readerSettings.openCSSFile',
)}
onSave={text => dispatch(setReaderSettings('customCSS', text))}
/>
<ConfirmationDialog
title={getString(
'moreScreen.settingsScreen.readerSettings.clearCustomCSS',
)}
visible={clearCSSModal.value}
onSubmit={() => {
dispatch(setReaderSettings('customCSS', ''));
}}
onDismiss={clearCSSModal.setFalse}
theme={theme}
/>
</Portal>
</>
Expand Down
Loading

0 comments on commit 3b2ee3d

Please sign in to comment.