You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-07-16 00:14:34 +02:00
This commit is contained in:
@ -686,7 +686,6 @@ packages/app-mobile/components/SelectDateTimeDialog.js
|
|||||||
packages/app-mobile/components/SideMenu.js
|
packages/app-mobile/components/SideMenu.js
|
||||||
packages/app-mobile/components/SideMenuContentNote.js
|
packages/app-mobile/components/SideMenuContentNote.js
|
||||||
packages/app-mobile/components/TextInput.js
|
packages/app-mobile/components/TextInput.js
|
||||||
packages/app-mobile/components/ToggleSpaceButton.js
|
|
||||||
packages/app-mobile/components/accessibility/AccessibleModalMenu.js
|
packages/app-mobile/components/accessibility/AccessibleModalMenu.js
|
||||||
packages/app-mobile/components/accessibility/AccessibleView.test.js
|
packages/app-mobile/components/accessibility/AccessibleView.test.js
|
||||||
packages/app-mobile/components/accessibility/AccessibleView.js
|
packages/app-mobile/components/accessibility/AccessibleView.js
|
||||||
@ -859,7 +858,7 @@ packages/app-mobile/utils/fs-driver/testUtil/createFilesFromPathRecord.js
|
|||||||
packages/app-mobile/utils/fs-driver/testUtil/verifyDirectoryMatches.js
|
packages/app-mobile/utils/fs-driver/testUtil/verifyDirectoryMatches.js
|
||||||
packages/app-mobile/utils/getPackageInfo.js
|
packages/app-mobile/utils/getPackageInfo.js
|
||||||
packages/app-mobile/utils/getVersionInfoText.js
|
packages/app-mobile/utils/getVersionInfoText.js
|
||||||
packages/app-mobile/utils/hooks/useKeyboardVisible.js
|
packages/app-mobile/utils/hooks/useKeyboardState.js
|
||||||
packages/app-mobile/utils/hooks/useOnLongPressProps.js
|
packages/app-mobile/utils/hooks/useOnLongPressProps.js
|
||||||
packages/app-mobile/utils/hooks/useReduceMotionEnabled.js
|
packages/app-mobile/utils/hooks/useReduceMotionEnabled.js
|
||||||
packages/app-mobile/utils/image/fileToImage.web.js
|
packages/app-mobile/utils/image/fileToImage.web.js
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -661,7 +661,6 @@ packages/app-mobile/components/SelectDateTimeDialog.js
|
|||||||
packages/app-mobile/components/SideMenu.js
|
packages/app-mobile/components/SideMenu.js
|
||||||
packages/app-mobile/components/SideMenuContentNote.js
|
packages/app-mobile/components/SideMenuContentNote.js
|
||||||
packages/app-mobile/components/TextInput.js
|
packages/app-mobile/components/TextInput.js
|
||||||
packages/app-mobile/components/ToggleSpaceButton.js
|
|
||||||
packages/app-mobile/components/accessibility/AccessibleModalMenu.js
|
packages/app-mobile/components/accessibility/AccessibleModalMenu.js
|
||||||
packages/app-mobile/components/accessibility/AccessibleView.test.js
|
packages/app-mobile/components/accessibility/AccessibleView.test.js
|
||||||
packages/app-mobile/components/accessibility/AccessibleView.js
|
packages/app-mobile/components/accessibility/AccessibleView.js
|
||||||
@ -834,7 +833,7 @@ packages/app-mobile/utils/fs-driver/testUtil/createFilesFromPathRecord.js
|
|||||||
packages/app-mobile/utils/fs-driver/testUtil/verifyDirectoryMatches.js
|
packages/app-mobile/utils/fs-driver/testUtil/verifyDirectoryMatches.js
|
||||||
packages/app-mobile/utils/getPackageInfo.js
|
packages/app-mobile/utils/getPackageInfo.js
|
||||||
packages/app-mobile/utils/getVersionInfoText.js
|
packages/app-mobile/utils/getVersionInfoText.js
|
||||||
packages/app-mobile/utils/hooks/useKeyboardVisible.js
|
packages/app-mobile/utils/hooks/useKeyboardState.js
|
||||||
packages/app-mobile/utils/hooks/useOnLongPressProps.js
|
packages/app-mobile/utils/hooks/useOnLongPressProps.js
|
||||||
packages/app-mobile/utils/hooks/useReduceMotionEnabled.js
|
packages/app-mobile/utils/hooks/useReduceMotionEnabled.js
|
||||||
packages/app-mobile/utils/image/fileToImage.web.js
|
packages/app-mobile/utils/image/fileToImage.web.js
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
|
|
||||||
// On some devices, the SafeAreaView conflicts with the KeyboardAvoidingView, creating
|
|
||||||
// additional (or a lack of additional) space at the bottom of the screen. Because this
|
|
||||||
// is different on different devices, this button allows toggling additional space a the bottom
|
|
||||||
// of the screen to compensate.
|
|
||||||
|
|
||||||
// Works around https://github.com/facebook/react-native/issues/13393 by adding additional
|
|
||||||
// space below the given component when the keyboard is visible unless a button is pressed.
|
|
||||||
|
|
||||||
import Setting from '@joplin/lib/models/Setting';
|
|
||||||
import { themeStyle } from '@joplin/lib/theme';
|
|
||||||
|
|
||||||
import * as React from 'react';
|
|
||||||
import { ReactNode, useCallback, useState, useEffect } from 'react';
|
|
||||||
import { Platform, useWindowDimensions, View, ViewStyle } from 'react-native';
|
|
||||||
import IconButton from './IconButton';
|
|
||||||
import useKeyboardVisible from '../utils/hooks/useKeyboardVisible';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
children: ReactNode;
|
|
||||||
themeId: number;
|
|
||||||
style?: ViewStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
const ToggleSpaceButton = (props: Props) => {
|
|
||||||
const [additionalSpace, setAdditionalSpace] = useState(0);
|
|
||||||
const [decreaseSpaceBtnVisible, setDecreaseSpaceBtnVisible] = useState(true);
|
|
||||||
|
|
||||||
// Some devices need space added, others need space removed.
|
|
||||||
const additionalPositiveSpace = 14;
|
|
||||||
const additionalNegativeSpace = -14;
|
|
||||||
|
|
||||||
// Switch from adding +14px to -14px.
|
|
||||||
const onDecreaseSpace = useCallback(() => {
|
|
||||||
setAdditionalSpace(additionalNegativeSpace);
|
|
||||||
setDecreaseSpaceBtnVisible(false);
|
|
||||||
Setting.setValue('editor.mobile.removeSpaceBelowToolbar', true);
|
|
||||||
}, [setAdditionalSpace, setDecreaseSpaceBtnVisible, additionalNegativeSpace]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (Setting.value('editor.mobile.removeSpaceBelowToolbar')) {
|
|
||||||
onDecreaseSpace();
|
|
||||||
}
|
|
||||||
}, [onDecreaseSpace]);
|
|
||||||
|
|
||||||
const theme = themeStyle(props.themeId);
|
|
||||||
|
|
||||||
const decreaseSpaceButton = (
|
|
||||||
<>
|
|
||||||
<View style={{
|
|
||||||
height: additionalPositiveSpace,
|
|
||||||
zIndex: -2,
|
|
||||||
}} />
|
|
||||||
<IconButton
|
|
||||||
themeId={props.themeId}
|
|
||||||
description={'Move toolbar to bottom of screen'}
|
|
||||||
containerStyle={{
|
|
||||||
height: additionalPositiveSpace,
|
|
||||||
width: '100%',
|
|
||||||
|
|
||||||
// Ensure that the icon is near the bottom of the screen,
|
|
||||||
// and thus invisible on devices where it isn't necessary.
|
|
||||||
position: 'absolute',
|
|
||||||
bottom: 0,
|
|
||||||
|
|
||||||
// Don't show the button on top of views with content.
|
|
||||||
zIndex: -1,
|
|
||||||
|
|
||||||
alignItems: 'center',
|
|
||||||
}}
|
|
||||||
onPress={onDecreaseSpace}
|
|
||||||
|
|
||||||
iconName='material chevron-down'
|
|
||||||
iconStyle={{ color: theme.color }}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
const { keyboardVisible } = useKeyboardVisible();
|
|
||||||
const windowSize = useWindowDimensions();
|
|
||||||
const isPortrait = windowSize.height > windowSize.width;
|
|
||||||
const spaceApplicable = keyboardVisible && Platform.OS === 'ios' && isPortrait;
|
|
||||||
|
|
||||||
const style: ViewStyle = {
|
|
||||||
marginBottom: spaceApplicable ? additionalSpace : 0,
|
|
||||||
...props.style,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={style}>
|
|
||||||
{props.children}
|
|
||||||
{ decreaseSpaceBtnVisible && spaceApplicable ? decreaseSpaceButton : null }
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ToggleSpaceButton;
|
|
@ -2,15 +2,12 @@ import * as React from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import NotesScreen from './screens/Notes';
|
import NotesScreen from './screens/Notes';
|
||||||
import SearchScreen from './screens/SearchScreen';
|
import SearchScreen from './screens/SearchScreen';
|
||||||
import { Component } from 'react';
|
import { KeyboardAvoidingView, Platform, View } from 'react-native';
|
||||||
import { KeyboardAvoidingView, Keyboard, Platform, View, KeyboardEvent, Dimensions, EmitterSubscription } from 'react-native';
|
|
||||||
import { AppState } from '../utils/types';
|
import { AppState } from '../utils/types';
|
||||||
import { themeStyle } from './global-style';
|
import { themeStyle } from './global-style';
|
||||||
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
interface State {
|
import useKeyboardState from '../utils/hooks/useKeyboardState';
|
||||||
autoCompletionBarExtraHeight: number;
|
import usePrevious from '@joplin/lib/hooks/usePrevious';
|
||||||
floatingKeyboardEnabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
@ -22,107 +19,58 @@ interface Props {
|
|||||||
themeId: number;
|
themeId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppNavComponent extends Component<Props, State> {
|
const AppNavComponent: React.FC<Props> = (props) => {
|
||||||
private previousRouteName_: string|null = null;
|
const keyboardState = useKeyboardState();
|
||||||
private keyboardDidShowListener: EmitterSubscription|null = null;
|
const safeAreaPadding = useSafeAreaInsets();
|
||||||
private keyboardDidHideListener: EmitterSubscription|null = null;
|
|
||||||
private keyboardWillChangeFrameListener: EmitterSubscription|null = null;
|
|
||||||
|
|
||||||
public constructor(props: Props) {
|
if (!props.route) throw new Error('Route must not be null');
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.previousRouteName_ = null;
|
// Note: certain screens are kept into memory, in particular Notes and Search
|
||||||
this.state = {
|
// so that the scroll position is not lost when the user navigate away from them.
|
||||||
autoCompletionBarExtraHeight: 0, // Extra padding for the auto completion bar at the top of the keyboard
|
|
||||||
floatingKeyboardEnabled: false,
|
const route = props.route;
|
||||||
};
|
let Screen = null;
|
||||||
|
let notesScreenVisible = false;
|
||||||
|
let searchScreenVisible = false;
|
||||||
|
|
||||||
|
if (route.routeName === 'Notes') {
|
||||||
|
notesScreenVisible = true;
|
||||||
|
} else if (route.routeName === 'Search') {
|
||||||
|
searchScreenVisible = true;
|
||||||
|
} else {
|
||||||
|
Screen = props.screens[route.routeName].screen;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UNSAFE_componentWillMount() {
|
const previousRouteName = usePrevious(route.routeName, '');
|
||||||
if (Platform.OS === 'ios') {
|
|
||||||
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this.keyboardDidShow.bind(this));
|
|
||||||
this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this.keyboardDidHide.bind(this));
|
|
||||||
this.keyboardWillChangeFrameListener = Keyboard.addListener('keyboardWillChangeFrame', this.keyboardWillChangeFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillUnmount() {
|
// Keep the search screen loaded if the user is viewing a note from that search screen
|
||||||
this.keyboardDidShowListener?.remove();
|
// so that if the back button is pressed, the screen is still loaded. However, unload
|
||||||
this.keyboardDidHideListener?.remove();
|
// it if navigating away.
|
||||||
this.keyboardWillChangeFrameListener?.remove();
|
const searchScreenLoaded = searchScreenVisible || (previousRouteName === 'Search' && route.routeName === 'Note');
|
||||||
|
|
||||||
this.keyboardDidShowListener = null;
|
const theme = themeStyle(props.themeId);
|
||||||
this.keyboardDidHideListener = null;
|
|
||||||
this.keyboardWillChangeFrameListener = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public keyboardDidShow() {
|
const style = { flex: 1, backgroundColor: theme.backgroundColor };
|
||||||
this.setState({ autoCompletionBarExtraHeight: 30 });
|
|
||||||
}
|
|
||||||
|
|
||||||
public keyboardDidHide() {
|
// When the floating keyboard is enabled, the KeyboardAvoidingView can have a very small
|
||||||
this.setState({ autoCompletionBarExtraHeight: 0 });
|
// height. Don't use the KeyboardAvoidingView when the floating keyboard is enabled.
|
||||||
}
|
// See https://github.com/facebook/react-native/issues/29473
|
||||||
|
const keyboardAvoidingViewEnabled = !keyboardState.isFloatingKeyboard;
|
||||||
|
const autocompletionBarPadding = Platform.OS === 'ios' && keyboardState.keyboardVisible ? safeAreaPadding.top : 0;
|
||||||
|
|
||||||
private keyboardWillChangeFrame = (evt: KeyboardEvent) => {
|
return (
|
||||||
const windowWidth = Dimensions.get('window').width;
|
<KeyboardAvoidingView
|
||||||
|
enabled={keyboardAvoidingViewEnabled}
|
||||||
// If the keyboard isn't as wide as the window, the floating keyboard is disabled.
|
behavior={Platform.OS === 'ios' ? 'padding' : null}
|
||||||
// See https://github.com/facebook/react-native/issues/29473#issuecomment-696658937
|
style={style}
|
||||||
this.setState({
|
>
|
||||||
floatingKeyboardEnabled: evt.endCoordinates.width < windowWidth,
|
<NotesScreen visible={notesScreenVisible} />
|
||||||
});
|
{searchScreenLoaded && <SearchScreen visible={searchScreenVisible} />}
|
||||||
};
|
{!notesScreenVisible && !searchScreenVisible && <Screen navigation={{ state: route }} themeId={props.themeId} dispatch={props.dispatch} />}
|
||||||
|
<View style={{ height: autocompletionBarPadding }} />
|
||||||
public render() {
|
</KeyboardAvoidingView>
|
||||||
if (!this.props.route) throw new Error('Route must not be null');
|
);
|
||||||
|
};
|
||||||
// Note: certain screens are kept into memory, in particular Notes and Search
|
|
||||||
// so that the scroll position is not lost when the user navigate away from them.
|
|
||||||
|
|
||||||
const route = this.props.route;
|
|
||||||
let Screen = null;
|
|
||||||
let notesScreenVisible = false;
|
|
||||||
let searchScreenVisible = false;
|
|
||||||
|
|
||||||
if (route.routeName === 'Notes') {
|
|
||||||
notesScreenVisible = true;
|
|
||||||
} else if (route.routeName === 'Search') {
|
|
||||||
searchScreenVisible = true;
|
|
||||||
} else {
|
|
||||||
Screen = this.props.screens[route.routeName].screen;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the search screen loaded if the user is viewing a note from that search screen
|
|
||||||
// so that if the back button is pressed, the screen is still loaded. However, unload
|
|
||||||
// it if navigating away.
|
|
||||||
const searchScreenLoaded = searchScreenVisible || (this.previousRouteName_ === 'Search' && route.routeName === 'Note');
|
|
||||||
|
|
||||||
this.previousRouteName_ = route.routeName;
|
|
||||||
|
|
||||||
const theme = themeStyle(this.props.themeId);
|
|
||||||
|
|
||||||
const style = { flex: 1, backgroundColor: theme.backgroundColor };
|
|
||||||
|
|
||||||
// When the floating keyboard is enabled, the KeyboardAvoidingView can have a very small
|
|
||||||
// height. Don't use the KeyboardAvoidingView when the floating keyboard is enabled.
|
|
||||||
// See https://github.com/facebook/react-native/issues/29473
|
|
||||||
const keyboardAvoidingViewEnabled = !this.state.floatingKeyboardEnabled;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<KeyboardAvoidingView
|
|
||||||
enabled={keyboardAvoidingViewEnabled}
|
|
||||||
behavior={Platform.OS === 'ios' ? 'padding' : null}
|
|
||||||
style={style}
|
|
||||||
>
|
|
||||||
<NotesScreen visible={notesScreenVisible} />
|
|
||||||
{searchScreenLoaded && <SearchScreen visible={searchScreenVisible} />}
|
|
||||||
{!notesScreenVisible && !searchScreenVisible && <Screen navigation={{ state: route }} themeId={this.props.themeId} dispatch={this.props.dispatch} />}
|
|
||||||
<View style={{ height: this.state.autoCompletionBarExtraHeight }} />
|
|
||||||
</KeyboardAvoidingView>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const AppNav = connect((state: AppState) => {
|
const AppNav = connect((state: AppState) => {
|
||||||
return {
|
return {
|
||||||
|
@ -61,7 +61,6 @@ import { DialogContext, DialogControl } from '../../DialogManager';
|
|||||||
import { CommandRuntimeProps, EditorMode, PickerResponse } from './types';
|
import { CommandRuntimeProps, EditorMode, PickerResponse } from './types';
|
||||||
import commands from './commands';
|
import commands from './commands';
|
||||||
import { AttachFileAction, AttachFileOptions } from './commands/attachFile';
|
import { AttachFileAction, AttachFileOptions } from './commands/attachFile';
|
||||||
import ToggleSpaceButton from '../../ToggleSpaceButton';
|
|
||||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||||
import PluginUserWebView from '../../plugins/dialogs/PluginUserWebView';
|
import PluginUserWebView from '../../plugins/dialogs/PluginUserWebView';
|
||||||
import getShownPluginEditorView from '@joplin/lib/services/plugins/utils/getShownPluginEditorView';
|
import getShownPluginEditorView from '@joplin/lib/services/plugins/utils/getShownPluginEditorView';
|
||||||
@ -1675,19 +1674,6 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderWrappedContent = () => {
|
|
||||||
const content = <>
|
|
||||||
{bodyComponent}
|
|
||||||
{renderVoiceTypingDialogs()}
|
|
||||||
</>;
|
|
||||||
|
|
||||||
return this.state.mode === 'edit' ? (
|
|
||||||
<ToggleSpaceButton themeId={this.props.themeId} style={this.styles().toggleSpaceButtonContent}>
|
|
||||||
{content}
|
|
||||||
</ToggleSpaceButton>
|
|
||||||
) : content;
|
|
||||||
};
|
|
||||||
|
|
||||||
const { editorPlugin: activeEditorPlugin } = getActivePluginEditorView(this.props.plugins);
|
const { editorPlugin: activeEditorPlugin } = getActivePluginEditorView(this.props.plugins);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -1709,7 +1695,8 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
|||||||
title={getDisplayParentTitle(this.state.note, this.state.folder)}
|
title={getDisplayParentTitle(this.state.note, this.state.folder)}
|
||||||
/>
|
/>
|
||||||
{titleComp}
|
{titleComp}
|
||||||
{renderWrappedContent()}
|
{bodyComponent}
|
||||||
|
{renderVoiceTypingDialogs()}
|
||||||
{renderActionButton()}
|
{renderActionButton()}
|
||||||
|
|
||||||
<SelectDateTimeDialog themeId={this.props.themeId} shown={this.state.alarmDialogShown} date={dueDate} onAccept={this.onAlarmDialogAccept} onReject={this.onAlarmDialogReject} />
|
<SelectDateTimeDialog themeId={this.props.themeId} shown={this.state.alarmDialogShown} date={dueDate} onAccept={this.onAlarmDialogAccept} onReject={this.onAlarmDialogReject} />
|
||||||
|
35
packages/app-mobile/utils/hooks/useKeyboardState.ts
Normal file
35
packages/app-mobile/utils/hooks/useKeyboardState.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { Dimensions, Keyboard } from 'react-native';
|
||||||
|
|
||||||
|
const useKeyboardState = () => {
|
||||||
|
const [keyboardVisible, setKeyboardVisible] = useState(false);
|
||||||
|
const [hasSoftwareKeyboard, setHasSoftwareKeyboard] = useState(false);
|
||||||
|
const [isFloatingKeyboard, setIsFloatingKeyboard] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
const showListener = Keyboard.addListener('keyboardDidShow', () => {
|
||||||
|
setKeyboardVisible(true);
|
||||||
|
setHasSoftwareKeyboard(true);
|
||||||
|
});
|
||||||
|
const hideListener = Keyboard.addListener('keyboardDidHide', () => {
|
||||||
|
setKeyboardVisible(false);
|
||||||
|
});
|
||||||
|
const floatingListener = Keyboard.addListener('keyboardWillChangeFrame', (evt) => {
|
||||||
|
const windowWidth = Dimensions.get('window').width;
|
||||||
|
// If the keyboard isn't as wide as the window, the floating keyboard is disabled.
|
||||||
|
// See https://github.com/facebook/react-native/issues/29473#issuecomment-696658937
|
||||||
|
setIsFloatingKeyboard(evt.endCoordinates.width < windowWidth);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (() => {
|
||||||
|
showListener.remove();
|
||||||
|
hideListener.remove();
|
||||||
|
floatingListener.remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
return { keyboardVisible, hasSoftwareKeyboard, isFloatingKeyboard };
|
||||||
|
}, [keyboardVisible, hasSoftwareKeyboard, isFloatingKeyboard]);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useKeyboardState;
|
@ -1,27 +0,0 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react';
|
|
||||||
import { Keyboard } from 'react-native';
|
|
||||||
|
|
||||||
const useKeyboardVisible = () => {
|
|
||||||
const [keyboardVisible, setKeyboardVisible] = useState(false);
|
|
||||||
const [hasSoftwareKeyboard, setHasSoftwareKeyboard] = useState(false);
|
|
||||||
useEffect(() => {
|
|
||||||
const showListener = Keyboard.addListener('keyboardDidShow', () => {
|
|
||||||
setKeyboardVisible(true);
|
|
||||||
setHasSoftwareKeyboard(true);
|
|
||||||
});
|
|
||||||
const hideListener = Keyboard.addListener('keyboardDidHide', () => {
|
|
||||||
setKeyboardVisible(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (() => {
|
|
||||||
showListener.remove();
|
|
||||||
hideListener.remove();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return useMemo(() => {
|
|
||||||
return { keyboardVisible, hasSoftwareKeyboard };
|
|
||||||
}, [keyboardVisible, hasSoftwareKeyboard]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useKeyboardVisible;
|
|
@ -839,22 +839,6 @@ const builtInMetadata = (Setting: typeof SettingType) => {
|
|||||||
isGlobal: true,
|
isGlobal: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// Works around a bug in which additional space is visible beneath the toolbar on some devices.
|
|
||||||
// See https://github.com/laurent22/joplin/pull/6823
|
|
||||||
'editor.mobile.removeSpaceBelowToolbar': {
|
|
||||||
value: false,
|
|
||||||
type: SettingItemType.Bool,
|
|
||||||
section: 'note',
|
|
||||||
public: true,
|
|
||||||
appTypes: [AppType.Mobile],
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
|
||||||
show: (settings: any) => settings['editor.mobile.removeSpaceBelowToolbar'],
|
|
||||||
label: () => 'Remove extra space below the markdown toolbar',
|
|
||||||
description: () => 'Works around bug on some devices where the markdown toolbar does not touch the bottom of the screen.',
|
|
||||||
storage: SettingStorage.File,
|
|
||||||
isGlobal: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
newTodoFocus: {
|
newTodoFocus: {
|
||||||
value: 'title',
|
value: 'title',
|
||||||
type: SettingItemType.String,
|
type: SettingItemType.String,
|
||||||
|
Reference in New Issue
Block a user