mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-21 09:38:01 +02:00
Revert: Mobile: Add note bar (#6772)
Revert commit dfd95f8385
Due to UX issues.
Ref https://discourse.joplinapp.org/t/25775/30
This commit is contained in:
parent
afc34b44c8
commit
44e60bdda9
@ -954,12 +954,6 @@ packages/app-mobile/components/NoteEditor/SelectionFormatting.js.map
|
||||
packages/app-mobile/components/NoteEditor/types.d.ts
|
||||
packages/app-mobile/components/NoteEditor/types.js
|
||||
packages/app-mobile/components/NoteEditor/types.js.map
|
||||
packages/app-mobile/components/NotesBar.d.ts
|
||||
packages/app-mobile/components/NotesBar.js
|
||||
packages/app-mobile/components/NotesBar.js.map
|
||||
packages/app-mobile/components/NotesBarListItem.d.ts
|
||||
packages/app-mobile/components/NotesBarListItem.js
|
||||
packages/app-mobile/components/NotesBarListItem.js.map
|
||||
packages/app-mobile/components/ScreenHeader.d.ts
|
||||
packages/app-mobile/components/ScreenHeader.js
|
||||
packages/app-mobile/components/ScreenHeader.js.map
|
||||
@ -969,18 +963,12 @@ packages/app-mobile/components/SelectDateTimeDialog.js.map
|
||||
packages/app-mobile/components/SideMenu.d.ts
|
||||
packages/app-mobile/components/SideMenu.js
|
||||
packages/app-mobile/components/SideMenu.js.map
|
||||
packages/app-mobile/components/checkbox.d.ts
|
||||
packages/app-mobile/components/checkbox.js
|
||||
packages/app-mobile/components/checkbox.js.map
|
||||
packages/app-mobile/components/getResponsiveValue.d.ts
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/getResponsiveValue.js.map
|
||||
packages/app-mobile/components/getResponsiveValue.test.d.ts
|
||||
packages/app-mobile/components/getResponsiveValue.test.js
|
||||
packages/app-mobile/components/getResponsiveValue.test.js.map
|
||||
packages/app-mobile/components/global-style.d.ts
|
||||
packages/app-mobile/components/global-style.js
|
||||
packages/app-mobile/components/global-style.js.map
|
||||
packages/app-mobile/components/screens/ConfigScreen.d.ts
|
||||
packages/app-mobile/components/screens/ConfigScreen.js
|
||||
packages/app-mobile/components/screens/ConfigScreen.js.map
|
||||
@ -993,12 +981,6 @@ packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js.map
|
||||
packages/app-mobile/components/screens/encryption-config.d.ts
|
||||
packages/app-mobile/components/screens/encryption-config.js
|
||||
packages/app-mobile/components/screens/encryption-config.js.map
|
||||
packages/app-mobile/components/searchNotes.d.ts
|
||||
packages/app-mobile/components/searchNotes.js
|
||||
packages/app-mobile/components/searchNotes.js.map
|
||||
packages/app-mobile/components/useStyles.d.ts
|
||||
packages/app-mobile/components/useStyles.js
|
||||
packages/app-mobile/components/useStyles.js.map
|
||||
packages/app-mobile/gulpfile.d.ts
|
||||
packages/app-mobile/gulpfile.js
|
||||
packages/app-mobile/gulpfile.js.map
|
||||
|
@ -29,7 +29,6 @@ module.exports = {
|
||||
|
||||
// React Native variables
|
||||
'__DEV__': 'readonly',
|
||||
'JSX': 'readonly',
|
||||
|
||||
// Clipper variables
|
||||
'browserSupportsPromises_': true,
|
||||
|
18
.gitignore
vendored
18
.gitignore
vendored
@ -942,12 +942,6 @@ packages/app-mobile/components/NoteEditor/SelectionFormatting.js.map
|
||||
packages/app-mobile/components/NoteEditor/types.d.ts
|
||||
packages/app-mobile/components/NoteEditor/types.js
|
||||
packages/app-mobile/components/NoteEditor/types.js.map
|
||||
packages/app-mobile/components/NotesBar.d.ts
|
||||
packages/app-mobile/components/NotesBar.js
|
||||
packages/app-mobile/components/NotesBar.js.map
|
||||
packages/app-mobile/components/NotesBarListItem.d.ts
|
||||
packages/app-mobile/components/NotesBarListItem.js
|
||||
packages/app-mobile/components/NotesBarListItem.js.map
|
||||
packages/app-mobile/components/ScreenHeader.d.ts
|
||||
packages/app-mobile/components/ScreenHeader.js
|
||||
packages/app-mobile/components/ScreenHeader.js.map
|
||||
@ -957,18 +951,12 @@ packages/app-mobile/components/SelectDateTimeDialog.js.map
|
||||
packages/app-mobile/components/SideMenu.d.ts
|
||||
packages/app-mobile/components/SideMenu.js
|
||||
packages/app-mobile/components/SideMenu.js.map
|
||||
packages/app-mobile/components/checkbox.d.ts
|
||||
packages/app-mobile/components/checkbox.js
|
||||
packages/app-mobile/components/checkbox.js.map
|
||||
packages/app-mobile/components/getResponsiveValue.d.ts
|
||||
packages/app-mobile/components/getResponsiveValue.js
|
||||
packages/app-mobile/components/getResponsiveValue.js.map
|
||||
packages/app-mobile/components/getResponsiveValue.test.d.ts
|
||||
packages/app-mobile/components/getResponsiveValue.test.js
|
||||
packages/app-mobile/components/getResponsiveValue.test.js.map
|
||||
packages/app-mobile/components/global-style.d.ts
|
||||
packages/app-mobile/components/global-style.js
|
||||
packages/app-mobile/components/global-style.js.map
|
||||
packages/app-mobile/components/screens/ConfigScreen.d.ts
|
||||
packages/app-mobile/components/screens/ConfigScreen.js
|
||||
packages/app-mobile/components/screens/ConfigScreen.js.map
|
||||
@ -981,12 +969,6 @@ packages/app-mobile/components/screens/UpgradeSyncTargetScreen.js.map
|
||||
packages/app-mobile/components/screens/encryption-config.d.ts
|
||||
packages/app-mobile/components/screens/encryption-config.js
|
||||
packages/app-mobile/components/screens/encryption-config.js.map
|
||||
packages/app-mobile/components/searchNotes.d.ts
|
||||
packages/app-mobile/components/searchNotes.js
|
||||
packages/app-mobile/components/searchNotes.js.map
|
||||
packages/app-mobile/components/useStyles.d.ts
|
||||
packages/app-mobile/components/useStyles.js
|
||||
packages/app-mobile/components/useStyles.js.map
|
||||
packages/app-mobile/gulpfile.d.ts
|
||||
packages/app-mobile/gulpfile.js
|
||||
packages/app-mobile/gulpfile.js.map
|
||||
|
@ -86,9 +86,5 @@
|
||||
"node-gyp": "^8.4.1",
|
||||
"nodemon": "^2.0.9"
|
||||
},
|
||||
"packageManager": "yarn@3.1.1",
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.14",
|
||||
"@types/react-dom": "17.0.14"
|
||||
}
|
||||
"packageManager": "yarn@3.1.1"
|
||||
}
|
||||
|
@ -1,293 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import { View, Text, TextInput, TouchableOpacity, FlatList, StyleSheet } from 'react-native';
|
||||
import { State } from '@joplin/lib/reducer';
|
||||
import { themeStyle } from './global-style';
|
||||
const { connect } = require('react-redux');
|
||||
const Icon = require('react-native-vector-icons/Ionicons').default;
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
import { Style } from './global-style';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import NotesBarListItem from './NotesBarListItem';
|
||||
import Folder from '@joplin/lib/models/Folder';
|
||||
import searchNotes from './searchNotes';
|
||||
|
||||
interface Props {
|
||||
themeId: number;
|
||||
notes: any[];
|
||||
todoCheckbox_change: (checked: boolean)=> void;
|
||||
selectedFolderId: string;
|
||||
activeFolderId: string;
|
||||
dispatch: any;
|
||||
selectedNoteId: string;
|
||||
settings: any;
|
||||
}
|
||||
|
||||
function NotesBarComponent(props: Props) {
|
||||
|
||||
const [query, setQuery] = React.useState<string>('');
|
||||
const [notes, setNotes] = React.useState<any[]>(props.notes);
|
||||
const theme: Style = React.useMemo(() => themeStyle(props.themeId), [props.themeId]);
|
||||
|
||||
const styles = (): Style => {
|
||||
const styles: Style = {
|
||||
container: {
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
backgroundColor: theme.backgroundColor3,
|
||||
},
|
||||
horizontalFlex: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
title: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
titleText: {
|
||||
fontSize: 16,
|
||||
},
|
||||
closeIcon: {
|
||||
fontSize: 30,
|
||||
paddingTop: 8,
|
||||
paddingBottom: 8,
|
||||
paddingRight: theme.marginRight,
|
||||
paddingLeft: theme.marginLeft,
|
||||
},
|
||||
top: {
|
||||
color: theme.color,
|
||||
},
|
||||
topContainer: {
|
||||
width: '100%',
|
||||
justifyContent: 'space-between',
|
||||
paddingLeft: theme.marginLeft,
|
||||
},
|
||||
padding: {
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: theme.marginRight,
|
||||
paddingTop: 12,
|
||||
paddingBottom: 12,
|
||||
},
|
||||
titleIcon: {
|
||||
fontSize: 22,
|
||||
marginRight: 4,
|
||||
},
|
||||
divider: {
|
||||
backgroundColor: theme.dividerColor,
|
||||
height: 1,
|
||||
width: '100%',
|
||||
},
|
||||
nativeInput: {
|
||||
fontSize: theme.fontSize,
|
||||
flex: 1,
|
||||
paddingRight: 8,
|
||||
},
|
||||
searchIcon: {
|
||||
fontSize: 22,
|
||||
},
|
||||
searchInput: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: theme.backgroundColor,
|
||||
paddingLeft: 8,
|
||||
borderRadius: 4,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.dividerColor,
|
||||
height: 42,
|
||||
flex: 1,
|
||||
},
|
||||
button: {
|
||||
height: 42,
|
||||
width: 42,
|
||||
backgroundColor: theme.color4,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 4,
|
||||
flex: 0.5,
|
||||
marginLeft: 8,
|
||||
},
|
||||
buttonIcon: {
|
||||
color: theme.backgroundColor,
|
||||
fontSize: 22,
|
||||
},
|
||||
inputGroup: {
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
};
|
||||
|
||||
return StyleSheet.create(styles);
|
||||
};
|
||||
|
||||
const titleComp = (
|
||||
<View style={[styles().title, styles().horizontalFlex]}>
|
||||
<Icon name='md-document'style={[styles().top, styles().titleIcon]} />
|
||||
<Text style={[styles().top, styles().titleText]}>{_('Notes')}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const dividerComp = (
|
||||
<View style={styles().divider}></View>
|
||||
);
|
||||
|
||||
const handleNotesBarClose = () => {
|
||||
props.dispatch({ type: 'NOTES_BAR_CLOSE' });
|
||||
};
|
||||
|
||||
const closeButtonComp = (
|
||||
<TouchableOpacity
|
||||
onPress={handleNotesBarClose}
|
||||
accessibilityLabel={_('Toggle note list')}
|
||||
accessibilityRole="button"
|
||||
>
|
||||
<Icon name="close" style={[styles().top, styles().closeIcon]}/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
|
||||
const renderIconButton = (icon: JSX.Element, onPress: ()=> Promise<void>, label: string) => {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles().button}
|
||||
activeOpacity={0.8}
|
||||
onPress={onPress}
|
||||
accessibilityLabel={label}
|
||||
accessibilityRole="button"
|
||||
>
|
||||
{icon}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const handleNewNote = async (isTodo: boolean) => {
|
||||
let folderId = props.selectedFolderId !== Folder.conflictFolderId() ? props.selectedFolderId : null;
|
||||
if (!folderId) folderId = props.activeFolderId;
|
||||
|
||||
props.dispatch({
|
||||
type: 'NAV_BACK',
|
||||
});
|
||||
|
||||
const newNote = await Note.save({
|
||||
parent_id: folderId,
|
||||
is_todo: isTodo ? 1 : 0,
|
||||
}, { provisional: true });
|
||||
|
||||
props.dispatch({
|
||||
type: 'NAV_GO',
|
||||
routeName: 'Note',
|
||||
noteId: newNote.id,
|
||||
});
|
||||
};
|
||||
|
||||
const addNoteButtonComp = renderIconButton(<Icon name='document-text-outline' style={styles().buttonIcon} />, () => handleNewNote(false), _('New note'));
|
||||
const addTodoButtonComp = renderIconButton(<Icon name='checkbox-outline' style={styles().buttonIcon} />, () => handleNewNote(true), _('New to-do'));
|
||||
|
||||
const topComp = (
|
||||
<View>
|
||||
<View style={[styles().topContainer, styles().horizontalFlex]}>
|
||||
{titleComp}
|
||||
{closeButtonComp}
|
||||
</View>
|
||||
{dividerComp}
|
||||
</View>
|
||||
);
|
||||
|
||||
const refreshSearch = async () => {
|
||||
const notes = await searchNotes(query, props.settings['db.ftsEnabled'], props.dispatch);
|
||||
setNotes(notes);
|
||||
};
|
||||
|
||||
const handleQuerySubmit = async () => {
|
||||
const trimmedQuery = query.trim();
|
||||
|
||||
if (!trimmedQuery) {
|
||||
props.dispatch({
|
||||
type: 'SEARCH_QUERY',
|
||||
query: '',
|
||||
});
|
||||
} else {
|
||||
props.dispatch({
|
||||
type: 'SEARCH_QUERY',
|
||||
query: trimmedQuery,
|
||||
});
|
||||
}
|
||||
|
||||
setQuery(trimmedQuery);
|
||||
await refreshSearch();
|
||||
};
|
||||
|
||||
const searchInputComp = (
|
||||
<View style={[styles().horizontalFlex, styles().searchInput]}>
|
||||
<Icon name='search' style={[styles().top, styles().searchIcon]}/>
|
||||
|
||||
<TextInput style={[styles().top, styles().nativeInput]} placeholder='Search' onChangeText={setQuery} value={query} onSubmitEditing={handleQuerySubmit} placeholderTextColor={theme.dividerColor} />
|
||||
</View>
|
||||
);
|
||||
|
||||
const inputGroupComp = (
|
||||
<View style={{ width: '100%' }}>
|
||||
<View style={[styles().padding, styles().horizontalFlex, styles().inputGroup]}>
|
||||
{searchInputComp}
|
||||
{addNoteButtonComp}
|
||||
{addTodoButtonComp}
|
||||
</View>
|
||||
{dividerComp}
|
||||
</View>
|
||||
);
|
||||
|
||||
let flatListRef: any = React.useRef(null);
|
||||
|
||||
const onRenderItem = React.useCallback(({ item }: { item: any }) => {
|
||||
if (item.is_todo) {
|
||||
return <NotesBarListItem note={item} todoCheckbox_change={props.todoCheckbox_change} />;
|
||||
} else {
|
||||
return <NotesBarListItem note={item} />;
|
||||
}
|
||||
}, [props.todoCheckbox_change]);
|
||||
|
||||
const NotesBarListComp = (
|
||||
<FlatList
|
||||
data={notes}
|
||||
renderItem={onRenderItem}
|
||||
keyExtractor={(item: any) => item.id}
|
||||
getItemLayout={(data, index) => (
|
||||
{
|
||||
length: data.length,
|
||||
offset: (theme.fontSize + styles().padding.paddingTop + styles().padding.paddingBottom) * index,
|
||||
viewOffset: (theme.fontSize + styles().padding.paddingTop + styles().padding.paddingBottom),
|
||||
index,
|
||||
}
|
||||
)}
|
||||
ref={(ref: any) => { flatListRef = ref; }}
|
||||
/>
|
||||
);
|
||||
|
||||
// Scroll the notesbar to selected note item after rendering
|
||||
React.useEffect(() => {
|
||||
const selectedItemIndex = notes.findIndex(item => item.id === props.selectedNoteId);
|
||||
if (selectedItemIndex >= 0) {
|
||||
flatListRef.scrollToIndex({ index: selectedItemIndex });
|
||||
}
|
||||
});
|
||||
|
||||
// Update the notesbar when a note item changes
|
||||
React.useEffect(() => {
|
||||
setNotes(props.notes);
|
||||
}, [props.notes]);
|
||||
|
||||
return (
|
||||
<View style={styles().container}>
|
||||
{topComp}
|
||||
{inputGroupComp}
|
||||
{ NotesBarListComp }
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const NotesBar = connect((state: State) => {
|
||||
return {
|
||||
themeId: state.settings.theme,
|
||||
notes: state.notes,
|
||||
activeFolderId: state.settings.activeFolderId,
|
||||
selectedFolderId: state.selectedFolderId,
|
||||
selectedNoteId: state.selectedNoteIds[0],
|
||||
settings: state.settings,
|
||||
};
|
||||
})(NotesBarComponent);
|
||||
|
||||
export default NotesBar;
|
@ -1,132 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import Checkbox from './checkbox';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native';
|
||||
import { Style } from './global-style';
|
||||
import { State } from '@joplin/lib/reducer';
|
||||
const { connect } = require('react-redux');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
import shim from '@joplin/lib/shim';
|
||||
import { themeStyle } from './global-style';
|
||||
|
||||
|
||||
interface NoteListProps {
|
||||
note: any;
|
||||
themeId: number;
|
||||
todoCheckbox_change: (checked: boolean)=> void;
|
||||
dispatch: Function;
|
||||
selectedNoteId: string;
|
||||
}
|
||||
|
||||
const NotesBarListItemComponent = function(props: NoteListProps) {
|
||||
const note = props.note ?? {};
|
||||
const isTodo = !!Number(note.is_todo);
|
||||
|
||||
const styles = (): Style => {
|
||||
const themeId = props.themeId;
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
const styles: Style = {
|
||||
horizontalFlex: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
padding: {
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: theme.marginRight,
|
||||
paddingTop: 12,
|
||||
paddingBottom: 12,
|
||||
},
|
||||
button: {
|
||||
height: 42,
|
||||
width: 42,
|
||||
backgroundColor: theme.color4,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: 4,
|
||||
flex: 0.5,
|
||||
marginLeft: 8,
|
||||
},
|
||||
itemText: {
|
||||
fontSize: theme.fontSize,
|
||||
color: theme.color,
|
||||
paddingTop: 12,
|
||||
paddingBottom: 12,
|
||||
},
|
||||
checkbox: {
|
||||
paddingRight: 10,
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingTop: 12,
|
||||
paddingBottom: 12,
|
||||
color: theme.color,
|
||||
},
|
||||
selectedItem: props.selectedNoteId === note.id ? {
|
||||
backgroundColor: theme.dividerColor,
|
||||
} : null,
|
||||
item: {
|
||||
borderBottomWidth: 1,
|
||||
borderColor: theme.dividerColor,
|
||||
},
|
||||
};
|
||||
|
||||
return StyleSheet.create(styles);
|
||||
};
|
||||
|
||||
const onTodoCheckboxChange = async (checked: boolean) => {
|
||||
await props.todoCheckbox_change(checked);
|
||||
};
|
||||
|
||||
const onPress = async () => {
|
||||
if (!note) return;
|
||||
if (note.encryption_applied) return;
|
||||
|
||||
props.dispatch({
|
||||
type: 'NAV_BACK',
|
||||
});
|
||||
|
||||
shim.setTimeout(() => {
|
||||
props.dispatch({
|
||||
type: 'NAV_GO',
|
||||
routeName: 'Note',
|
||||
noteId: note.id,
|
||||
});
|
||||
}, 5);
|
||||
};
|
||||
|
||||
const noteTitle = Note.displayTitle(note);
|
||||
let item;
|
||||
|
||||
if (isTodo) {
|
||||
item = (
|
||||
<View>
|
||||
<TouchableOpacity style={[styles().horizontalFlex, styles().item, styles().selectedItem]} onPress={onPress}>
|
||||
<Checkbox
|
||||
style={styles().checkbox}
|
||||
checked={!!Number(note.todo_completed)}
|
||||
onChange={(checked) => onTodoCheckboxChange(checked)}
|
||||
accessibilityLabel={_('to-do: %s', noteTitle)}
|
||||
/>
|
||||
<Text style={styles().itemText}>{noteTitle}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
} else {
|
||||
item = (
|
||||
<View>
|
||||
<TouchableOpacity onPress={onPress} style={[styles().selectedItem, styles().item]}>
|
||||
<Text style={[styles().itemText, styles().padding]}>{noteTitle}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
const NotesBarListItem = connect((state: State) => {
|
||||
return {
|
||||
themeId: state.settings.theme,
|
||||
selectedNoteId: state.selectedNoteIds[0],
|
||||
};
|
||||
})(NotesBarListItemComponent);
|
||||
|
||||
export default NotesBarListItem;
|
@ -1,93 +0,0 @@
|
||||
import * as React from 'react';
|
||||
const Component = React.Component;
|
||||
const { View, TouchableHighlight } = require('react-native');
|
||||
const Icon = require('react-native-vector-icons/Ionicons').default;
|
||||
Icon.loadFont();
|
||||
|
||||
interface Style {
|
||||
[key: string]: any;
|
||||
}
|
||||
interface Props {
|
||||
style: Style;
|
||||
checked: boolean;
|
||||
onChange: (checked: boolean)=> void;
|
||||
accessibilityLabel?: string;
|
||||
}
|
||||
|
||||
interface State {
|
||||
checked: boolean;
|
||||
}
|
||||
|
||||
const styles: Style = {
|
||||
checkboxIcon: {
|
||||
fontSize: 20,
|
||||
height: 22,
|
||||
// marginRight: 10,
|
||||
},
|
||||
};
|
||||
|
||||
class Checkbox extends Component<Props, State> {
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
checked: false,
|
||||
};
|
||||
}
|
||||
|
||||
public UNSAFE_componentWillMount() {
|
||||
this.setState({ checked: this.props.checked });
|
||||
}
|
||||
|
||||
public UNSAFE_componentWillReceiveProps(newProps: Props) {
|
||||
if ('checked' in newProps) {
|
||||
this.setState({ checked: newProps.checked });
|
||||
}
|
||||
}
|
||||
|
||||
private onPress() {
|
||||
const newChecked = !this.state.checked;
|
||||
this.setState({ checked: newChecked });
|
||||
if (this.props.onChange) this.props.onChange(newChecked);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const iconName = this.state.checked ? 'md-checkbox-outline' : 'md-square-outline';
|
||||
|
||||
const style: Style = this.props.style ? Object.assign({}, this.props.style) : {};
|
||||
style.justifyContent = 'center';
|
||||
style.alignItems = 'center';
|
||||
|
||||
const checkboxIconStyle = Object.assign({}, styles.checkboxIcon);
|
||||
if (style.color) checkboxIconStyle.color = style.color;
|
||||
|
||||
if (style.paddingTop) checkboxIconStyle.marginTop = style.paddingTop;
|
||||
if (style.paddingBottom) checkboxIconStyle.marginBottom = style.paddingBottom;
|
||||
if (style.paddingLeft) checkboxIconStyle.marginLeft = style.paddingLeft;
|
||||
if (style.paddingRight) checkboxIconStyle.marginRight = style.paddingRight;
|
||||
|
||||
const thStyle = {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
};
|
||||
|
||||
if (style && style.display === 'none') return <View />;
|
||||
|
||||
// if (style.display) thStyle.display = style.display;
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
onPress={() => this.onPress()}
|
||||
style={thStyle}
|
||||
accessibilityRole="checkbox"
|
||||
accessibilityState={{
|
||||
checked: this.state.checked,
|
||||
}}
|
||||
accessibilityLabel={this.props.accessibilityLabel ?? ''}>
|
||||
<Icon name={iconName} style={checkboxIconStyle} />
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Checkbox;
|
@ -1,115 +0,0 @@
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
const { Platform } = require('react-native');
|
||||
import { themeById } from '@joplin/lib/theme';
|
||||
|
||||
export interface Style {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface Fonts {
|
||||
[key: number]: string;
|
||||
}
|
||||
|
||||
interface ThemeCache {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const baseStyle = {
|
||||
appearance: 'light',
|
||||
fontSize: 16,
|
||||
noteViewerFontSize: 16,
|
||||
margin: 15, // No text and no interactive component should be within this margin
|
||||
itemMarginTop: 10,
|
||||
itemMarginBottom: 10,
|
||||
fontSizeSmaller: 14,
|
||||
disabledOpacity: 0.2,
|
||||
lineHeight: '1.6em',
|
||||
};
|
||||
|
||||
const themeCache_: ThemeCache = {};
|
||||
|
||||
function addExtraStyles(style: Style) {
|
||||
style.marginRight = style.margin;
|
||||
style.marginLeft = style.margin;
|
||||
style.marginTop = style.margin;
|
||||
style.marginBottom = style.margin;
|
||||
|
||||
style.icon = {
|
||||
color: style.color,
|
||||
fontSize: 30,
|
||||
};
|
||||
|
||||
style.lineInput = {
|
||||
color: style.color,
|
||||
backgroundColor: style.backgroundColor,
|
||||
borderBottomWidth: 1,
|
||||
borderColor: style.dividerColor,
|
||||
paddingBottom: 0,
|
||||
};
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
delete style.lineInput.borderBottomWidth;
|
||||
delete style.lineInput.borderColor;
|
||||
}
|
||||
|
||||
style.buttonRow = {
|
||||
flexDirection: 'row',
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: style.dividerColor,
|
||||
paddingTop: 10,
|
||||
};
|
||||
|
||||
style.normalText = {
|
||||
color: style.color,
|
||||
fontSize: style.fontSize,
|
||||
};
|
||||
|
||||
style.urlText = {
|
||||
color: style.urlColor,
|
||||
fontSize: style.fontSize,
|
||||
};
|
||||
|
||||
style.headerStyle = {
|
||||
color: style.color,
|
||||
fontSize: style.fontSize * 1.2,
|
||||
fontWeight: 'bold',
|
||||
};
|
||||
|
||||
style.headerWrapperStyle = {
|
||||
backgroundColor: style.headerBackgroundColor,
|
||||
};
|
||||
|
||||
style.keyboardAppearance = style.appearance;
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
export function editorFont(fontId?: number) {
|
||||
// IMPORTANT: The font mapping must match the one in Setting.js
|
||||
const fonts: Fonts = {
|
||||
[Setting.FONT_DEFAULT]: null,
|
||||
[Setting.FONT_MENLO]: 'Menlo',
|
||||
[Setting.FONT_COURIER_NEW]: 'Courier New',
|
||||
[Setting.FONT_AVENIR]: 'Avenir',
|
||||
[Setting.FONT_MONOSPACE]: 'monospace',
|
||||
};
|
||||
if (!fontId) {
|
||||
// console.warn('Editor font not set! Falling back to default font."');
|
||||
fontId = Setting.FONT_DEFAULT;
|
||||
}
|
||||
return fonts[fontId];
|
||||
}
|
||||
|
||||
export function themeStyle(theme?: number) {
|
||||
if (!theme) {
|
||||
console.warn('Theme not set! Defaulting to Light theme.');
|
||||
theme = Setting.THEME_LIGHT;
|
||||
}
|
||||
|
||||
const cacheKey = [theme].join('-');
|
||||
if (themeCache_[cacheKey]) return themeCache_[cacheKey];
|
||||
|
||||
const output = Object.assign({}, baseStyle, themeById(theme));
|
||||
themeCache_[cacheKey] = addExtraStyles(output);
|
||||
return themeCache_[cacheKey];
|
||||
}
|
@ -2,7 +2,7 @@ const React = require('react');
|
||||
const Component = React.Component;
|
||||
const { connect } = require('react-redux');
|
||||
const { Text, TouchableOpacity, View, StyleSheet } = require('react-native');
|
||||
const Checkbox = require('./checkbox.js').default;
|
||||
const { Checkbox } = require('./checkbox.js');
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
const time = require('@joplin/lib/time').default;
|
||||
const { themeStyle } = require('./global-style.js');
|
||||
|
@ -3,7 +3,6 @@ import uuid from '@joplin/lib/uuid';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import UndoRedoService from '@joplin/lib/services/UndoRedoService';
|
||||
import { State } from '@joplin/lib/reducer';
|
||||
import NoteBodyViewer from '../NoteBodyViewer/NoteBodyViewer';
|
||||
import checkPermissions from '../../utils/checkPermissions';
|
||||
import NoteEditor from '../NoteEditor/NoteEditor';
|
||||
@ -11,7 +10,7 @@ import { ChangeEvent, UndoRedoDepthChangeEvent } from '../NoteEditor/types';
|
||||
|
||||
const FileViewer = require('react-native-file-viewer').default;
|
||||
const React = require('react');
|
||||
import { Platform, Keyboard, View, TextInput, StyleSheet, Linking, Image, Share, PermissionsAndroid, Animated, TouchableOpacity, Dimensions, PanResponder } from 'react-native';
|
||||
const { Platform, Keyboard, View, TextInput, StyleSheet, Linking, Image, Share, PermissionsAndroid } = require('react-native');
|
||||
const { connect } = require('react-redux');
|
||||
// const { MarkdownEditor } = require('@joplin/lib/../MarkdownEditor/index.js');
|
||||
const RNFS = require('react-native-fs');
|
||||
@ -30,12 +29,12 @@ const mimeUtils = require('@joplin/lib/mime-utils.js').mime;
|
||||
import ScreenHeader from '../ScreenHeader';
|
||||
const NoteTagsDialog = require('./NoteTagsDialog');
|
||||
import time from '@joplin/lib/time';
|
||||
import Checkbox from '../checkbox';
|
||||
const { Checkbox } = require('../checkbox.js');
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
import ResourceFetcher from '@joplin/lib/services/ResourceFetcher';
|
||||
const { BaseScreenComponent } = require('../base-screen.js');
|
||||
import { themeStyle, editorFont } from '../global-style';
|
||||
const { themeStyle, editorFont } = require('../global-style.js');
|
||||
const { dialogs } = require('../../utils/dialogs.js');
|
||||
const DialogBox = require('react-native-dialogbox').default;
|
||||
const DocumentPicker = require('react-native-document-picker').default;
|
||||
@ -46,23 +45,20 @@ import { ImagePickerResponse } from 'react-native-image-picker';
|
||||
import SelectDateTimeDialog from '../SelectDateTimeDialog';
|
||||
import ShareExtension from '../../utils/ShareExtension.js';
|
||||
import CameraView from '../CameraView';
|
||||
import NotesBar from '../NotesBar';
|
||||
import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
import Logger from '@joplin/lib/Logger';
|
||||
const urlUtils = require('@joplin/lib/urlUtils');
|
||||
const Icon = require('react-native-vector-icons/Feather').default;
|
||||
import getResponsiveValue from '../getResponsiveValue';
|
||||
|
||||
const emptyArray: any[] = [];
|
||||
|
||||
const logger = Logger.create('screens/Note');
|
||||
|
||||
class NoteScreenComponent extends BaseScreenComponent {
|
||||
public static navigationOptions(): any {
|
||||
static navigationOptions(): any {
|
||||
return { header: null };
|
||||
}
|
||||
|
||||
public constructor() {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
note: Note.new(),
|
||||
@ -91,9 +87,6 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
canUndo: false,
|
||||
canRedo: false,
|
||||
},
|
||||
|
||||
notesBarWidth: this.getNotesBarWidth(),
|
||||
isTablet: Dimensions.get('window').width >= 768,
|
||||
};
|
||||
|
||||
this.saveActionQueues_ = {};
|
||||
@ -205,7 +198,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
if (msg.indexOf('file://') === 0) {
|
||||
throw new Error(_('Links with protocol "%s" are not supported', 'file://'));
|
||||
} else {
|
||||
await Linking.openURL(msg);
|
||||
Linking.openURL(msg);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@ -246,8 +239,6 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
this.onBodyViewerCheckboxChange = this.onBodyViewerCheckboxChange.bind(this);
|
||||
this.onBodyChange = this.onBodyChange.bind(this);
|
||||
this.onUndoRedoDepthChange = this.onUndoRedoDepthChange.bind(this);
|
||||
this.onNotesBarToggle = this.onNotesBarToggle.bind(this);
|
||||
this.handleScreenWidthChange_ = this.handleScreenWidthChange_.bind(this);
|
||||
}
|
||||
|
||||
private useEditorBeta(): boolean {
|
||||
@ -290,27 +281,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
});
|
||||
}
|
||||
|
||||
private getNotesBarWidth = () => {
|
||||
const notesBarWidth = getResponsiveValue({
|
||||
sm: 250,
|
||||
md: 260,
|
||||
lg: 270,
|
||||
xl: 280,
|
||||
xxl: 290,
|
||||
});
|
||||
|
||||
return notesBarWidth;
|
||||
};
|
||||
|
||||
// Update state that depends on the screen width when the screen width changes ( the device orientation changess)
|
||||
private handleScreenWidthChange_() {
|
||||
this.setState({
|
||||
notesBarWidth: this.getNotesBarWidth(),
|
||||
isTablet: Dimensions.get('window').width >= 768,
|
||||
});
|
||||
}
|
||||
|
||||
private screenHeader_undoButtonPress() {
|
||||
screenHeader_undoButtonPress() {
|
||||
if (this.useEditorBeta()) {
|
||||
this.editorRef.current.undo();
|
||||
} else {
|
||||
@ -318,7 +289,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private screenHeader_redoButtonPress() {
|
||||
screenHeader_redoButtonPress() {
|
||||
if (this.useEditorBeta()) {
|
||||
this.editorRef.current.redo();
|
||||
} else {
|
||||
@ -326,13 +297,13 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private undoState(noteBody: string = null) {
|
||||
undoState(noteBody: string = null) {
|
||||
return {
|
||||
body: noteBody === null ? this.state.note.body : noteBody,
|
||||
};
|
||||
}
|
||||
|
||||
private styles() {
|
||||
styles() {
|
||||
const themeId = this.props.themeId;
|
||||
const theme = themeStyle(themeId);
|
||||
|
||||
@ -351,7 +322,6 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
flex: 1,
|
||||
paddingLeft: theme.marginLeft,
|
||||
paddingRight: theme.marginRight,
|
||||
paddingBottom: Platform.OS === 'ios' ? 40 : 0,
|
||||
|
||||
// Add extra space to allow scrolling past end of document, and also to fix this:
|
||||
// https://github.com/laurent22/joplin/issues/1437
|
||||
@ -417,84 +387,17 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
paddingBottom: 10, // Added for iOS (Not needed for Android??)
|
||||
};
|
||||
|
||||
styles.noteMainComp = {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
position: 'relative',
|
||||
};
|
||||
|
||||
styles.notesBarContainer = {
|
||||
position: 'relative',
|
||||
left: this.notesBarPosition,
|
||||
top: 0,
|
||||
width: this.state.notesBarWidth,
|
||||
height: '100%',
|
||||
};
|
||||
|
||||
styles.noteComp = {
|
||||
position: 'relative',
|
||||
top: 0,
|
||||
left: this.notePosition,
|
||||
width: this.noteWidth,
|
||||
};
|
||||
|
||||
styles.noteActionButton = {
|
||||
width: 54,
|
||||
height: 54,
|
||||
backgroundColor: theme.backgroundColor3,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.dividerColor,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
};
|
||||
|
||||
styles.noteActionButtonActive = {
|
||||
...styles.noteActionButton,
|
||||
borderWidth: 0,
|
||||
backgroundColor: theme.color4,
|
||||
};
|
||||
|
||||
styles.noteActionButton1 = {
|
||||
borderBottomWidth: 0,
|
||||
borderTopLeftRadius: 8,
|
||||
borderTopRightRadius: 8,
|
||||
};
|
||||
|
||||
styles.noteActionButton2 = {
|
||||
// Removing this temporarily till second noteAction is implemented
|
||||
// borderBottomLeftRadius: 8,
|
||||
// borderBottomRightRadius: 8,
|
||||
borderRadius: 8,
|
||||
};
|
||||
|
||||
styles.noteActionButtonIcon = {
|
||||
fontSize: 30,
|
||||
color: theme.color,
|
||||
};
|
||||
|
||||
styles.noteActionButtonIconActive = {
|
||||
...styles.noteActionButtonIcon,
|
||||
color: theme.backgroundColor,
|
||||
};
|
||||
|
||||
styles.noteActionButtonGroup = {
|
||||
position: 'absolute',
|
||||
top: '8%',
|
||||
right: '3%',
|
||||
transform: [{ translateY: this.noteActionsPositionY }],
|
||||
};
|
||||
|
||||
if (this.state.HACK_webviewLoadingState === 1) styles.titleTextInput.marginTop = 1;
|
||||
|
||||
this.styles_[cacheKey] = StyleSheet.create(styles);
|
||||
return this.styles_[cacheKey];
|
||||
}
|
||||
|
||||
private isModified() {
|
||||
isModified() {
|
||||
return shared.isModified(this);
|
||||
}
|
||||
|
||||
private async requestGeoLocationPermissions() {
|
||||
async requestGeoLocationPermissions() {
|
||||
if (!Setting.value('trackLocation')) return;
|
||||
|
||||
const response = await checkPermissions(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, {
|
||||
@ -511,7 +414,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
async componentDidMount() {
|
||||
BackButtonService.addHandler(this.backHandler);
|
||||
NavService.addHandler(this.navHandler);
|
||||
|
||||
@ -532,75 +435,13 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
// has already been granted, it doesn't slow down opening the note. If it hasn't
|
||||
// been granted, the popup will open anyway.
|
||||
void this.requestGeoLocationPermissions();
|
||||
|
||||
this.unsubscribeScreenWidthChangeHandler_ = Dimensions.addEventListener('change', this.handleScreenWidthChange_);
|
||||
}
|
||||
|
||||
private animateNotesBarOpen = () => {
|
||||
Animated.parallel([
|
||||
Animated.spring(
|
||||
this.notesBarPosition,
|
||||
{
|
||||
toValue: 0,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
),
|
||||
Animated.spring(
|
||||
this.notePosition,
|
||||
{
|
||||
toValue: 0,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
),
|
||||
Animated.spring(
|
||||
this.noteWidth,
|
||||
{
|
||||
toValue: Dimensions.get('window').width - this.state.notesBarWidth,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
),
|
||||
]).start();
|
||||
};
|
||||
|
||||
private animateNotesBarClose = () => {
|
||||
Animated.parallel([
|
||||
Animated.spring(
|
||||
this.notesBarPosition,
|
||||
{
|
||||
toValue: -1 * this.state.notesBarWidth,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
),
|
||||
Animated.spring(
|
||||
this.notePosition,
|
||||
{
|
||||
toValue: -1 * this.state.notesBarWidth,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
),
|
||||
Animated.spring(
|
||||
this.noteWidth,
|
||||
{
|
||||
toValue: Dimensions.get('window').width,
|
||||
useNativeDriver: false,
|
||||
}
|
||||
),
|
||||
]).start();
|
||||
};
|
||||
|
||||
private onNotesBarToggle = async () => {
|
||||
if (this.props.showNotesBar) {
|
||||
this.props.dispatch({ type: 'NOTES_BAR_CLOSE' });
|
||||
} else {
|
||||
this.props.dispatch({ type: 'NOTES_BAR_OPEN' });
|
||||
}
|
||||
};
|
||||
|
||||
private onMarkForDownload(event: any) {
|
||||
onMarkForDownload(event: any) {
|
||||
void ResourceFetcher.instance().markForDownload(event.resourceId);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: any) {
|
||||
componentDidUpdate(prevProps: any) {
|
||||
if (this.doFocusUpdate_) {
|
||||
this.doFocusUpdate_ = false;
|
||||
this.focusUpdate();
|
||||
@ -612,17 +453,9 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
options: this.sideMenuOptions(),
|
||||
});
|
||||
}
|
||||
|
||||
if (this.props.showNotesBar !== prevProps.showNotesBar) {
|
||||
if (this.props.showNotesBar) {
|
||||
this.animateNotesBarOpen();
|
||||
} else {
|
||||
this.animateNotesBarClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
componentWillUnmount() {
|
||||
BackButtonService.removeHandler(this.backHandler);
|
||||
NavService.removeHandler(this.navHandler);
|
||||
|
||||
@ -637,34 +470,15 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
// It cannot theoretically be undefined, since componentDidMount should always be called before
|
||||
// componentWillUnmount, but with React Native the impossible often becomes possible.
|
||||
if (this.undoRedoService_) this.undoRedoService_.off('stackChange', this.undoRedoService_stackChange);
|
||||
|
||||
if (this.unsubscribeScreenWidthChangeHandler_) {
|
||||
this.unsubscribeScreenWidthChangeHandler_.remove();
|
||||
this.unsubscribeScreenWidthChangeHandler_ = null;
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillMount() {
|
||||
if (this.props.showNotesBar) {
|
||||
this.notesBarPosition = new Animated.Value(0);
|
||||
this.notePosition = new Animated.Value(0);
|
||||
this.noteWidth = new Animated.Value(Dimensions.get('window').width - 250);
|
||||
} else {
|
||||
this.notesBarPosition = new Animated.Value(-1 * this.state.notesBarWidth);
|
||||
this.notePosition = new Animated.Value(-1 * this.state.notesBarWidth);
|
||||
this.noteWidth = new Animated.Value(Dimensions.get('window').width);
|
||||
}
|
||||
|
||||
this.noteActionsPositionY = new Animated.Value(0);
|
||||
}
|
||||
|
||||
private title_changeText(text: string) {
|
||||
title_changeText(text: string) {
|
||||
shared.noteComponent_change(this, 'title', text);
|
||||
this.setState({ newAndNoTitleChangeNoteId: null });
|
||||
this.scheduleSave();
|
||||
}
|
||||
|
||||
private body_changeText(text: string) {
|
||||
body_changeText(text: string) {
|
||||
if (!this.undoRedoService_.canUndo) {
|
||||
this.undoRedoService_.push(this.undoState());
|
||||
} else {
|
||||
@ -675,7 +489,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
this.scheduleSave();
|
||||
}
|
||||
|
||||
private body_selectionChange(event: any) {
|
||||
body_selectionChange(event: any) {
|
||||
if (this.useEditorBeta()) {
|
||||
this.selection = event.selection;
|
||||
} else {
|
||||
@ -683,34 +497,34 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private makeSaveAction() {
|
||||
makeSaveAction() {
|
||||
return async () => {
|
||||
return shared.saveNoteButton_press(this);
|
||||
};
|
||||
}
|
||||
|
||||
private saveActionQueue(noteId: string) {
|
||||
saveActionQueue(noteId: string) {
|
||||
if (!this.saveActionQueues_[noteId]) {
|
||||
this.saveActionQueues_[noteId] = new AsyncActionQueue(500);
|
||||
}
|
||||
return this.saveActionQueues_[noteId];
|
||||
}
|
||||
|
||||
private scheduleSave() {
|
||||
scheduleSave() {
|
||||
this.saveActionQueue(this.state.note.id).push(this.makeSaveAction());
|
||||
}
|
||||
|
||||
private async saveNoteButton_press(folderId: string = null) {
|
||||
async saveNoteButton_press(folderId: string = null) {
|
||||
await shared.saveNoteButton_press(this, folderId);
|
||||
|
||||
Keyboard.dismiss();
|
||||
}
|
||||
|
||||
private async saveOneProperty(name: string, value: any) {
|
||||
async saveOneProperty(name: string, value: any) {
|
||||
await shared.saveOneProperty(this, name, value);
|
||||
}
|
||||
|
||||
private async deleteNote_onPress() {
|
||||
async deleteNote_onPress() {
|
||||
const note = this.state.note;
|
||||
if (!note.id) return;
|
||||
|
||||
@ -743,7 +557,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private async imageDimensions(uri: string) {
|
||||
async imageDimensions(uri: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Image.getSize(
|
||||
uri,
|
||||
@ -757,7 +571,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
});
|
||||
}
|
||||
|
||||
private showImagePicker(options: any) {
|
||||
showImagePicker(options: any) {
|
||||
return new Promise((resolve) => {
|
||||
ImagePicker.launchImageLibrary(options, (response: any) => {
|
||||
resolve(response);
|
||||
@ -765,7 +579,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
});
|
||||
}
|
||||
|
||||
private async resizeImage(localFilePath: string, targetPath: string, mimeType: string) {
|
||||
async resizeImage(localFilePath: string, targetPath: string, mimeType: string) {
|
||||
const maxSize = Resource.IMAGE_MAX_DIMENSION;
|
||||
|
||||
const dimensions: any = await this.imageDimensions(localFilePath);
|
||||
@ -814,7 +628,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
return true;
|
||||
}
|
||||
|
||||
private async attachFile(pickerResponse: any, fileType: string) {
|
||||
async attachFile(pickerResponse: any, fileType: string) {
|
||||
if (!pickerResponse) {
|
||||
// User has cancelled
|
||||
return;
|
||||
@ -932,11 +746,11 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private takePhoto_onPress() {
|
||||
takePhoto_onPress() {
|
||||
this.setState({ showCamera: true });
|
||||
}
|
||||
|
||||
private cameraView_onPhoto(data: any) {
|
||||
cameraView_onPhoto(data: any) {
|
||||
void this.attachFile(
|
||||
{
|
||||
uri: data.uri,
|
||||
@ -948,7 +762,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
this.setState({ showCamera: false });
|
||||
}
|
||||
|
||||
private cameraView_onCancel() {
|
||||
cameraView_onCancel() {
|
||||
this.setState({ showCamera: false });
|
||||
}
|
||||
|
||||
@ -959,34 +773,34 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
private toggleIsTodo_onPress() {
|
||||
toggleIsTodo_onPress() {
|
||||
shared.toggleIsTodo_onPress(this);
|
||||
|
||||
this.scheduleSave();
|
||||
}
|
||||
|
||||
private tags_onPress() {
|
||||
tags_onPress() {
|
||||
if (!this.state.note || !this.state.note.id) return;
|
||||
|
||||
this.setState({ noteTagDialogShown: true });
|
||||
}
|
||||
|
||||
private async share_onPress() {
|
||||
async share_onPress() {
|
||||
await Share.share({
|
||||
message: `${this.state.note.title}\n\n${this.state.note.body}`,
|
||||
title: this.state.note.title,
|
||||
});
|
||||
}
|
||||
|
||||
private properties_onPress() {
|
||||
properties_onPress() {
|
||||
this.props.dispatch({ type: 'SIDE_MENU_OPEN' });
|
||||
}
|
||||
|
||||
public setAlarm_onPress() {
|
||||
setAlarm_onPress() {
|
||||
this.setState({ alarmDialogShown: true });
|
||||
}
|
||||
|
||||
private async onAlarmDialogAccept(date: Date) {
|
||||
async onAlarmDialogAccept(date: Date) {
|
||||
const newNote = Object.assign({}, this.state.note);
|
||||
newNote.todo_due = date ? date.getTime() : 0;
|
||||
|
||||
@ -995,40 +809,40 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
this.setState({ alarmDialogShown: false });
|
||||
}
|
||||
|
||||
private onAlarmDialogReject() {
|
||||
onAlarmDialogReject() {
|
||||
this.setState({ alarmDialogShown: false });
|
||||
}
|
||||
|
||||
private async showOnMap_onPress() {
|
||||
async showOnMap_onPress() {
|
||||
if (!this.state.note.id) return;
|
||||
|
||||
const note = await Note.load(this.state.note.id);
|
||||
try {
|
||||
const url = Note.geolocationUrl(note);
|
||||
await Linking.openURL(url);
|
||||
Linking.openURL(url);
|
||||
} catch (error) {
|
||||
this.props.dispatch({ type: 'SIDE_MENU_CLOSE' });
|
||||
await dialogs.error(this, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
private async showSource_onPress() {
|
||||
async showSource_onPress() {
|
||||
if (!this.state.note.id) return;
|
||||
|
||||
const note = await Note.load(this.state.note.id);
|
||||
try {
|
||||
await Linking.openURL(note.source_url);
|
||||
Linking.openURL(note.source_url);
|
||||
} catch (error) {
|
||||
await dialogs.error(this, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
private copyMarkdownLink_onPress() {
|
||||
copyMarkdownLink_onPress() {
|
||||
const note = this.state.note;
|
||||
Clipboard.setString(Note.markdownTag(note));
|
||||
}
|
||||
|
||||
private sideMenuOptions() {
|
||||
sideMenuOptions() {
|
||||
const note = this.state.note;
|
||||
if (!note) return [];
|
||||
|
||||
@ -1080,7 +894,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
if (buttonId === 'attachPhoto') void this.attachPhoto_onPress();
|
||||
}
|
||||
|
||||
private menuOptions() {
|
||||
menuOptions() {
|
||||
const note = this.state.note;
|
||||
const isTodo = note && !!note.is_todo;
|
||||
const isSaved = note && note.id;
|
||||
@ -1164,11 +978,11 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
return output;
|
||||
}
|
||||
|
||||
private async todoCheckbox_change(checked: boolean) {
|
||||
async todoCheckbox_change(checked: boolean) {
|
||||
await this.saveOneProperty('todo_completed', checked ? time.unixMs() : 0);
|
||||
}
|
||||
|
||||
public scheduleFocusUpdate() {
|
||||
scheduleFocusUpdate() {
|
||||
if (this.focusUpdateIID_) shim.clearTimeout(this.focusUpdateIID_);
|
||||
|
||||
this.focusUpdateIID_ = shim.setTimeout(() => {
|
||||
@ -1177,7 +991,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}, 100);
|
||||
}
|
||||
|
||||
private focusUpdate() {
|
||||
focusUpdate() {
|
||||
if (this.focusUpdateIID_) shim.clearTimeout(this.focusUpdateIID_);
|
||||
this.focusUpdateIID_ = null;
|
||||
|
||||
@ -1195,7 +1009,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
// }
|
||||
}
|
||||
|
||||
private async folderPickerOptions_valueChanged(itemValue: any) {
|
||||
async folderPickerOptions_valueChanged(itemValue: any) {
|
||||
const note = this.state.note;
|
||||
const isProvisionalNote = this.props.provisionalNoteIds.includes(note.id);
|
||||
|
||||
@ -1216,7 +1030,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
});
|
||||
}
|
||||
|
||||
private folderPickerOptions() {
|
||||
folderPickerOptions() {
|
||||
const options = {
|
||||
enabled: true,
|
||||
selectedFolderId: this.state.folder ? this.state.folder.id : null,
|
||||
@ -1229,7 +1043,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
return this.folderPickerOptions_;
|
||||
}
|
||||
|
||||
private onBodyViewerLoadEnd() {
|
||||
onBodyViewerLoadEnd() {
|
||||
shim.setTimeout(() => {
|
||||
this.setState({ HACK_webviewLoadingState: 1 });
|
||||
shim.setTimeout(() => {
|
||||
@ -1238,11 +1052,11 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}, 5);
|
||||
}
|
||||
|
||||
private onBodyViewerCheckboxChange(newBody: string) {
|
||||
onBodyViewerCheckboxChange(newBody: string) {
|
||||
void this.saveOneProperty('body', newBody);
|
||||
}
|
||||
|
||||
public render() {
|
||||
render() {
|
||||
if (this.state.isLoading) {
|
||||
return (
|
||||
<View style={this.styles().screen}>
|
||||
@ -1319,6 +1133,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
placeholderTextColor={theme.colorFaded}
|
||||
// need some extra padding for iOS so that the keyboard won't cover last line of the note
|
||||
// see https://github.com/laurent22/joplin/issues/3607
|
||||
paddingBottom={ Platform.OS === 'ios' ? 40 : 0}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
@ -1397,65 +1212,6 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
|
||||
const noteTagDialog = !this.state.noteTagDialogShown ? null : <NoteTagsDialog onCloseRequested={this.noteTagDialog_closeRequested} />;
|
||||
|
||||
// Different styles for when the note actions are active or not
|
||||
const notesBarToggleIconStyle = this.props.showNotesBar ? this.styles().noteActionButtonIconActive : this.styles().noteActionButtonIcon;
|
||||
const notesBarToggleStyle = this.props.showNotesBar ? this.styles().noteActionButtonActive : this.styles().noteActionButton;
|
||||
|
||||
const handleNoteActionsDrag = (gestureState: any) => {
|
||||
const minY = 160;
|
||||
const maxY = 0.8 * Dimensions.get('window').height;
|
||||
|
||||
let newY = gestureState.moveY;
|
||||
|
||||
if (newY < minY) {
|
||||
newY = minY;
|
||||
} else if (newY > maxY) {
|
||||
newY = maxY;
|
||||
}
|
||||
|
||||
this.noteActionsPositionY.setValue(newY - 162);
|
||||
};
|
||||
|
||||
// Pan responder that handles making the note actions draggable.
|
||||
// The note actions need to be draggable, because they could
|
||||
// potentially obstruct some portion of a note's content
|
||||
const noteActionsDragResponder = PanResponder.create({
|
||||
// Only start dragging after moving at least 10px — this prevents clicks from dragging instead
|
||||
// of triggering onPress events
|
||||
onMoveShouldSetPanResponder: (_evt, gestureState) => {
|
||||
return Math.abs(gestureState.dx) > 10 || Math.abs(gestureState.dy) > 10;
|
||||
},
|
||||
onPanResponderMove: (_e: any, gestureState: any) => {
|
||||
handleNoteActionsDrag(gestureState);
|
||||
},
|
||||
});
|
||||
|
||||
// Note actions are the notesbar and split layout toggle button
|
||||
const noteActionButtonGroupComp = (
|
||||
<Animated.View style={this.styles().noteActionButtonGroup} {...noteActionsDragResponder.panHandlers} >
|
||||
{/* Temporarily hiding the split layout button till it's implemented */}
|
||||
{/* <TouchableOpacity style={[this.styles().noteActionButton, this.styles().noteActionButton1]} activeOpacity={0.7}>
|
||||
<Icon name="columns" style={this.styles().noteActionButtonIcon} />
|
||||
</TouchableOpacity> */}
|
||||
<TouchableOpacity style={[notesBarToggleStyle, this.styles().noteActionButton2]} activeOpacity={0.7} onPress={this.onNotesBarToggle}>
|
||||
<Icon name="list" style={notesBarToggleIconStyle} />
|
||||
</TouchableOpacity>
|
||||
</Animated.View>
|
||||
);
|
||||
|
||||
const noteMainComp = (
|
||||
<View style={this.styles().noteMainComp}>
|
||||
<Animated.View style={this.styles().notesBarContainer}>
|
||||
<NotesBar todoCheckbox_change={this.todoCheckbox_change} />
|
||||
</Animated.View>
|
||||
<Animated.View style={this.styles().noteComp}>
|
||||
{titleComp}
|
||||
{bodyComponent}
|
||||
</Animated.View>
|
||||
{ this.state.isTablet && noteActionButtonGroupComp }
|
||||
</View>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={this.rootStyle(this.props.themeId).root}>
|
||||
<ScreenHeader
|
||||
@ -1472,7 +1228,8 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
onUndoButtonPress={this.screenHeader_undoButtonPress}
|
||||
onRedoButtonPress={this.screenHeader_redoButtonPress}
|
||||
/>
|
||||
{noteMainComp}
|
||||
{titleComp}
|
||||
{bodyComponent}
|
||||
{actionButtonComp}
|
||||
|
||||
<SelectDateTimeDialog themeId={this.props.themeId} shown={this.state.alarmDialogShown} date={dueDate} onAccept={this.onAlarmDialogAccept} onReject={this.onAlarmDialogReject} />
|
||||
@ -1488,7 +1245,7 @@ class NoteScreenComponent extends BaseScreenComponent {
|
||||
}
|
||||
}
|
||||
|
||||
const NoteScreen = connect((state: State) => {
|
||||
const NoteScreen = connect((state: any) => {
|
||||
return {
|
||||
noteId: state.selectedNoteIds.length ? state.selectedNoteIds[0] : null,
|
||||
noteHash: state.selectedNoteHash,
|
||||
@ -1504,7 +1261,6 @@ const NoteScreen = connect((state: State) => {
|
||||
provisionalNoteIds: state.provisionalNoteIds,
|
||||
highlightedWords: state.highlightedWords,
|
||||
useEditorBeta: state.settings['editor.beta'],
|
||||
showNotesBar: state.showMobileNotesBar,
|
||||
};
|
||||
})(NoteScreenComponent);
|
||||
|
||||
|
@ -5,12 +5,13 @@ const { connect } = require('react-redux');
|
||||
const { ScreenHeader } = require('../ScreenHeader');
|
||||
const Icon = require('react-native-vector-icons/Ionicons').default;
|
||||
const { _ } = require('@joplin/lib/locale');
|
||||
const Note = require('@joplin/lib/models/Note').default;
|
||||
const { NoteItem } = require('../note-item.js');
|
||||
const { BaseScreenComponent } = require('../base-screen.js');
|
||||
const { themeStyle } = require('../global-style.js');
|
||||
const DialogBox = require('react-native-dialogbox').default;
|
||||
const SearchEngineUtils = require('@joplin/lib/services/searchengine/SearchEngineUtils').default;
|
||||
const SearchEngine = require('@joplin/lib/services/searchengine/SearchEngine').default;
|
||||
import searchNotes from '../searchNotes';
|
||||
|
||||
Icon.loadFont();
|
||||
|
||||
@ -100,7 +101,25 @@ class SearchScreenComponent extends BaseScreenComponent {
|
||||
|
||||
query = query === null ? this.state.query.trim : query.trim();
|
||||
|
||||
const notes = await searchNotes(query, this.props.settings['db.ftsEnabled'], this.props.dispatch);
|
||||
let notes = [];
|
||||
|
||||
if (query) {
|
||||
if (this.props.settings['db.ftsEnabled']) {
|
||||
notes = await SearchEngineUtils.notesForQuery(query, true);
|
||||
} else {
|
||||
const p = query.split(' ');
|
||||
const temp = [];
|
||||
for (let i = 0; i < p.length; i++) {
|
||||
const t = p[i].trim();
|
||||
if (!t) continue;
|
||||
temp.push(t);
|
||||
}
|
||||
|
||||
notes = await Note.previews(null, {
|
||||
anywherePattern: `*${temp.join('*')}*`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isMounted_) return;
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
import SearchEngineUtils from '@joplin/lib/services/searchengine/SearchEngineUtils';
|
||||
import SearchEngine from '@joplin/lib/services/searchengine/SearchEngine';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import { NoteEntity } from '@joplin/lib/services/database/types';
|
||||
|
||||
// Returns notes from a search query and sets highlighted words
|
||||
// Be sure to use 'await' keyword or the function might not work properly
|
||||
// Eg. await HandleNoteQuery();
|
||||
|
||||
const searchNotes = async (query: string, dbFtsEnabled: boolean, dispatch: (action: Object)=> void): Promise<NoteEntity[]> => {
|
||||
let notes = [];
|
||||
|
||||
if (query) {
|
||||
if (dbFtsEnabled) {
|
||||
notes = await SearchEngineUtils.notesForQuery(query, true);
|
||||
} else {
|
||||
const p = query.split(' ');
|
||||
const temp = [];
|
||||
for (let i = 0; i < p.length; i++) {
|
||||
const t = p[i].trim();
|
||||
if (!t) continue;
|
||||
temp.push(t);
|
||||
}
|
||||
|
||||
notes = await Note.previews(null, {
|
||||
anywherePattern: `*${temp.join('*')}*`,
|
||||
});
|
||||
}
|
||||
|
||||
const parsedQuery = await SearchEngine.instance().parseQuery(query);
|
||||
const highlightedWords = SearchEngine.instance().allParsedQueryTerms(parsedQuery);
|
||||
|
||||
dispatch({
|
||||
type: 'SET_HIGHLIGHTED',
|
||||
words: highlightedWords,
|
||||
});
|
||||
}
|
||||
|
||||
return notes;
|
||||
};
|
||||
|
||||
export default searchNotes;
|
@ -1,12 +0,0 @@
|
||||
import { StyleSheet } from 'react-native';
|
||||
import { Style } from './global-style';
|
||||
import { themeStyle } from './global-style';
|
||||
|
||||
const useStyles = (stylingFunction: (theme: Style)=> Style, themeId?: number) => {
|
||||
const theme = themeStyle(themeId);
|
||||
const styles = stylingFunction(theme);
|
||||
|
||||
return StyleSheet.create(styles);
|
||||
};
|
||||
|
||||
export default useStyles;
|
@ -229,7 +229,7 @@ PODS:
|
||||
- React
|
||||
- react-native-get-random-values (1.7.1):
|
||||
- React-Core
|
||||
- react-native-image-picker (2.3.4):
|
||||
- react-native-image-picker (4.10.0):
|
||||
- React-Core
|
||||
- react-native-image-resizer (1.4.5):
|
||||
- React-Core
|
||||
@ -533,7 +533,7 @@ SPEC CHECKSUMS:
|
||||
react-native-document-picker: 20f652c2402d3ddc81f396d8167c3bd978add4a2
|
||||
react-native-geolocation: c956aeb136625c23e0dce0467664af2c437888c9
|
||||
react-native-get-random-values: 2c4ff6b44cb71291dabe9a8ae87d3877dcf387da
|
||||
react-native-image-picker: c6d75c4ab2cf46f9289f341242b219cb3c1180d3
|
||||
react-native-image-picker: 4bc9ed38c8be255b515d8c88babbaf74973f91a8
|
||||
react-native-image-resizer: d9fb629a867335bdc13230ac2a58702bb8c8828f
|
||||
react-native-netinfo: 3d3769f0d65de15c83a9bf1346f8be71de5a24bf
|
||||
react-native-rsa-native: 1f6bba06dd02f0e652a66a384c75c270f7a0062f
|
||||
|
@ -15,9 +15,5 @@ module.exports = {
|
||||
|
||||
testPathIgnorePatterns: ['<rootDir>/node_modules/'],
|
||||
|
||||
'transformIgnorePatterns': [
|
||||
'node_modules/(?!@codemirror)/',
|
||||
],
|
||||
|
||||
slowTestThreshold: 40,
|
||||
};
|
||||
|
@ -27,14 +27,11 @@
|
||||
"@react-native-community/netinfo": "^6.0.0",
|
||||
"@react-native-community/push-notification-ios": "^1.6.0",
|
||||
"@react-native-community/slider": "^3.0.3",
|
||||
"@types/react-test-renderer": "^18.0.0",
|
||||
"assert-browserify": "^2.0.0",
|
||||
"buffer": "^5.0.8",
|
||||
"constants-browserify": "^1.0.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"events": "^3.2.0",
|
||||
"jest": "^28.1.3",
|
||||
"jest-environment-jsdom": "^28.1.3",
|
||||
"joplin-rn-alarm-notification": "^1.0.5",
|
||||
"jsc-android": "241213.1.0",
|
||||
"md5": "^2.2.1",
|
||||
@ -92,21 +89,20 @@
|
||||
"@codemirror/view": "^6.0.0",
|
||||
"@joplin/tools": "~2.9",
|
||||
"@lezer/highlight": "^1.0.0",
|
||||
"@testing-library/react-native": "^11.0.0",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/jest": "^28.1.3",
|
||||
"@types/node": "^18.7.6",
|
||||
"@types/react-native": "^0.64.4",
|
||||
"@types/react-redux": "^7.1.24",
|
||||
"babel-plugin-module-resolver": "^4.1.0",
|
||||
"execa": "^4.0.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"gulp": "^4.0.2",
|
||||
"jest": "^28.1.1",
|
||||
"jest-environment-jsdom": "^28.1.3",
|
||||
"jetifier": "^1.6.5",
|
||||
"jsdom": "^20.0.0",
|
||||
"metro-react-native-babel-preset": "^0.66.2",
|
||||
"nodemon": "^2.0.12",
|
||||
"react-test-renderer": "17.0.2",
|
||||
"ts-jest": "^28.0.5",
|
||||
"ts-loader": "^9.3.1",
|
||||
"ts-node": "^10.9.1",
|
||||
|
@ -64,7 +64,7 @@ const { SearchScreen } = require('./components/screens/search.js');
|
||||
const { OneDriveLoginScreen } = require('./components/screens/onedrive-login.js');
|
||||
import EncryptionConfigScreen from './components/screens/encryption-config';
|
||||
const { DropboxLoginScreen } = require('./components/screens/dropbox-login.js');
|
||||
import { MenuProvider } from 'react-native-popup-menu';
|
||||
const { MenuContext } = require('react-native-popup-menu');
|
||||
import SideMenu from './components/SideMenu';
|
||||
const { SideMenuContent } = require('./components/side-menu-content.js');
|
||||
const { SideMenuContentNote } = require('./components/side-menu-content-note.js');
|
||||
@ -75,7 +75,7 @@ const { FileApiDriverLocal } = require('@joplin/lib/file-api-driver-local');
|
||||
import ResourceFetcher from '@joplin/lib/services/ResourceFetcher';
|
||||
import SearchEngine from '@joplin/lib/services/searchengine/SearchEngine';
|
||||
const WelcomeUtils = require('@joplin/lib/WelcomeUtils');
|
||||
import { themeStyle } from './components/global-style';
|
||||
const { themeStyle } = require('./components/global-style.js');
|
||||
import SyncTargetRegistry from '@joplin/lib/SyncTargetRegistry';
|
||||
const SyncTargetFilesystem = require('@joplin/lib/SyncTargetFilesystem.js');
|
||||
const SyncTargetNextcloud = require('@joplin/lib/SyncTargetNextcloud.js');
|
||||
@ -378,17 +378,6 @@ const appReducer = (state = appDefaultState, action: any) => {
|
||||
newState.isOnMobileData = action.isOnMobileData;
|
||||
break;
|
||||
|
||||
case 'NOTES_BAR_OPEN':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.showMobileNotesBar = true;
|
||||
break;
|
||||
|
||||
case 'NOTES_BAR_CLOSE':
|
||||
|
||||
newState = Object.assign({}, state);
|
||||
newState.showMobileNotesBar = false;
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
error.message = `In reducer: ${error.message} Action: ${JSON.stringify(action)}`;
|
||||
@ -930,7 +919,7 @@ class AppComponent extends React.Component {
|
||||
}}
|
||||
>
|
||||
<StatusBar barStyle={statusBarStyle} />
|
||||
<MenuProvider style={{ flex: 1 }}>
|
||||
<MenuContext style={{ flex: 1 }}>
|
||||
<SafeAreaView style={{ flex: 0, backgroundColor: theme.backgroundColor2 }}/>
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, backgroundColor: theme.backgroundColor }}>
|
||||
@ -939,7 +928,7 @@ class AppComponent extends React.Component {
|
||||
<DropdownAlert ref={(ref: any) => this.dropdownAlert_ = ref} tapToCloseEnabled={true} />
|
||||
<Animated.View pointerEvents='none' style={{ position: 'absolute', backgroundColor: 'black', opacity: this.state.sideMenuContentOpacity, width: '100%', height: '120%' }}/>
|
||||
</SafeAreaView>
|
||||
</MenuProvider>
|
||||
</MenuContext>
|
||||
</SideMenu>
|
||||
</View>
|
||||
);
|
||||
|
@ -13,7 +13,6 @@
|
||||
"tools/*.ts",
|
||||
],
|
||||
"compilerOptions": {
|
||||
"types": ["jest", "node", "react-test-renderer"],
|
||||
"allowSyntheticDefaultImports": true
|
||||
"types": ["jest", "node"]
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,6 @@ export interface State {
|
||||
hasEncryptedItems: boolean;
|
||||
needApiAuth: boolean;
|
||||
profileConfig: ProfileConfig;
|
||||
showMobileNotesBar: boolean;
|
||||
|
||||
// Extra reducer keys go here:
|
||||
pluginService: PluginServiceState;
|
||||
@ -157,7 +156,6 @@ export const defaultState: State = {
|
||||
},
|
||||
backwardHistoryNotes: [],
|
||||
forwardHistoryNotes: [],
|
||||
showMobileNotesBar: false,
|
||||
// pluginsLegacy is the original plugin system, which eventually was used only for GotoAnything.
|
||||
// GotoAnything should be refactored to part of core and when it's done the pluginsLegacy key can
|
||||
// be removed. It was originally named "plugins", then renamed "pluginsLegacy" so as not to conflict
|
||||
|
@ -23,7 +23,7 @@ const themes: any = {
|
||||
[Setting.THEME_OLED_DARK]: theme_oledDark,
|
||||
};
|
||||
|
||||
export function themeById(themeId: number) {
|
||||
export function themeById(themeId: string) {
|
||||
if (!themes[themeId]) throw new Error(`Invalid theme ID: ${themeId}`);
|
||||
const output = Object.assign({}, themes[themeId]);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user