You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-10 22:11:50 +02:00
Chore: Mobile: Update mobile components for compatibility with React Native 0.79 (#12154)
This commit is contained in:
@@ -205,7 +205,7 @@ class Dropdown extends Component<DropdownProps, DropdownState> {
|
||||
<View
|
||||
style={{ flexDirection: 'row', flex: 1, alignItems: 'center' }}
|
||||
onLayout={this.updateHeaderCoordinates}
|
||||
ref={ref => (this.headerRef = ref)}
|
||||
ref={ref => { this.headerRef = ref; } }
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={headerWrapperStyle}
|
||||
|
@@ -1,5 +1,4 @@
|
||||
const React = require('react');
|
||||
|
||||
import * as React from 'react';
|
||||
import { FunctionComponent, ReactElement } from 'react';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import Folder, { FolderEntityWithChildren } from '@joplin/lib/models/Folder';
|
||||
|
@@ -198,8 +198,8 @@ const useTooltipStyles = (themeId: number) => {
|
||||
// On web, by default, pressing buttons defocuses the active edit control, dismissing the
|
||||
// virtual keyboard. This hook creates listeners that optionally prevent the keyboard from dismissing.
|
||||
const usePreventKeyboardDismissTouchListeners = (preventKeyboardDismiss: boolean, onPress: ()=> void, disabled: boolean) => {
|
||||
const touchStartPointRef = useRef<[number, number]>();
|
||||
const isTapRef = useRef<boolean>();
|
||||
const touchStartPointRef = useRef<[number, number]>([-1, -1]);
|
||||
const isTapRef = useRef<boolean>(false);
|
||||
const onTouchStart = useCallback((event: GestureResponderEvent) => {
|
||||
if (Platform.OS === 'web' && preventKeyboardDismiss) {
|
||||
const touch = event.nativeEvent.touches[0];
|
||||
|
@@ -1,9 +1,8 @@
|
||||
// Dialog allowing the user to update/create links
|
||||
|
||||
const React = require('react');
|
||||
const { useState, useEffect, useMemo, useRef } = require('react');
|
||||
const { StyleSheet } = require('react-native');
|
||||
const { View, Text, TextInput, Button } = require('react-native');
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect, useMemo, useRef } from 'react';
|
||||
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
|
||||
|
||||
import Modal from '../Modal';
|
||||
import { themeStyle } from '@joplin/lib/theme';
|
||||
@@ -26,7 +25,7 @@ const EditLinkDialog = (props: LinkDialogProps) => {
|
||||
const [linkLabel, setLinkLabel] = useState('');
|
||||
const [linkURL, setLinkURL] = useState('');
|
||||
|
||||
const linkInputRef = useRef();
|
||||
const linkInputRef = useRef<TextInput|null>(null);
|
||||
|
||||
// Reset the label and URL when shown/hidden
|
||||
useEffect(() => {
|
||||
@@ -53,10 +52,6 @@ const EditLinkDialog = (props: LinkDialogProps) => {
|
||||
shadowOpacity: 0.4,
|
||||
shadowRadius: 1,
|
||||
},
|
||||
button: {
|
||||
color: theme.color2,
|
||||
backgroundColor: theme.backgroundColor2,
|
||||
},
|
||||
text: {
|
||||
color: theme.color,
|
||||
},
|
||||
@@ -146,7 +141,6 @@ const EditLinkDialog = (props: LinkDialogProps) => {
|
||||
{linkURLInput}
|
||||
</View>
|
||||
<Button
|
||||
style={styles.button}
|
||||
onPress={onSubmit}
|
||||
title={_('Done')}
|
||||
/>
|
||||
|
@@ -5,7 +5,7 @@ import Setting from '@joplin/lib/models/Setting';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import { themeStyle } from '@joplin/lib/theme';
|
||||
import { Theme } from '@joplin/lib/themes/type';
|
||||
import { MutableRefObject, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { BackHandler, Platform } from 'react-native';
|
||||
import ExtendedWebView from '../../ExtendedWebView';
|
||||
import { OnMessageEvent, WebViewControl } from '../../ExtendedWebView/types';
|
||||
@@ -83,7 +83,7 @@ const useCss = (editorTheme: Theme) => {
|
||||
|
||||
const ImageEditor = (props: Props) => {
|
||||
const editorTheme: Theme = themeStyle(props.themeId);
|
||||
const webviewRef: MutableRefObject<WebViewControl>|null = useRef(null);
|
||||
const webviewRef = useRef<WebViewControl|null>(null);
|
||||
const [imageChanged, setImageChanged] = useState(false);
|
||||
|
||||
const dialogs = useContext(DialogContext);
|
||||
@@ -124,10 +124,10 @@ const ImageEditor = (props: Props) => {
|
||||
onRequestCloseEditor(true);
|
||||
return true;
|
||||
};
|
||||
BackHandler.addEventListener('hardwareBackPress', hardwareBackPressListener);
|
||||
const handle = BackHandler.addEventListener('hardwareBackPress', hardwareBackPressListener);
|
||||
|
||||
return () => {
|
||||
BackHandler.removeEventListener('hardwareBackPress', hardwareBackPressListener);
|
||||
handle.remove();
|
||||
};
|
||||
}, [onRequestCloseEditor]);
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Displays a find/replace dialog
|
||||
|
||||
const React = require('react');
|
||||
const { useMemo, useState, useEffect } = require('react');
|
||||
import * as React from 'react';
|
||||
import { useMemo, useState, useEffect } from 'react';
|
||||
|
||||
import { EditorSettings } from './types';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
const React = require('react');
|
||||
import * as React from 'react';
|
||||
|
||||
import { Component } from 'react';
|
||||
|
||||
@@ -88,7 +88,7 @@ class NoteListComponent extends Component<NoteListProps> {
|
||||
|
||||
if (this.props.items.length) {
|
||||
return <FlatList
|
||||
ref={ref => (this.rootRef_ = ref)}
|
||||
ref={ref => { this.rootRef_ = ref; }}
|
||||
data={this.props.items}
|
||||
renderItem={({ item }) => <NoteItem note={item} />}
|
||||
keyExtractor={item => item.id}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
const React = require('react');
|
||||
import * as React from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
const { View, StyleSheet } = require('react-native');
|
||||
import { View, StyleSheet } from 'react-native';
|
||||
import createRootStyle from '../../utils/createRootStyle';
|
||||
import ScreenHeader from '../ScreenHeader';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { themeStyle } from './global-style';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
const { View, Button, Text, StyleSheet } = require('react-native');
|
||||
import { View, Button, Text, StyleSheet } from 'react-native';
|
||||
import time from '@joplin/lib/time';
|
||||
import { Platform } from 'react-native';
|
||||
import Modal from './Modal';
|
||||
@@ -157,11 +157,11 @@ export default class SelectDateTimeDialog extends React.PureComponent<any, any>
|
||||
}}
|
||||
>
|
||||
<View style={{ ...styles.modalView, backgroundColor: theme.backgroundColor }}>
|
||||
<View style={{ padding: 15, flexBasis: 'auto', paddingBottom: 0, flexGrow: 0, width: '100%', borderBottomWidth: 1, borderBottomColor: theme.dividerColor, borderBottomStyle: 'solid' }}>
|
||||
<View style={{ padding: 15, flexBasis: 'auto', paddingBottom: 0, flexGrow: 0, width: '100%', borderBottomWidth: 1, borderBottomColor: theme.dividerColor }}>
|
||||
<Text style={{ ...styles.modalText, color: theme.color, fontSize: 14, fontWeight: 'bold' }}>{_('Set alarm')}</Text>
|
||||
</View>
|
||||
{this.renderContent()}
|
||||
<View style={{ padding: 20, flexBasis: 'auto', borderTopWidth: 1, borderTopStyle: 'solid', borderTopColor: theme.dividerColor }}>
|
||||
<View style={{ padding: 20, flexBasis: 'auto', borderTopWidth: 1, borderTopColor: theme.dividerColor }}>
|
||||
<View style={{ marginBottom: 10 }}>
|
||||
<Button title={_('Save alarm')} onPress={() => this.onAccept()} key="saveButton" />
|
||||
</View>
|
||||
|
@@ -15,9 +15,11 @@ type Option = {
|
||||
isDivider: true;
|
||||
};
|
||||
|
||||
export type SideMenuContentOptions = Option[];
|
||||
|
||||
interface Props {
|
||||
themeId: number;
|
||||
options: Option[];
|
||||
options: SideMenuContentOptions;
|
||||
}
|
||||
|
||||
const useStyles = (themeId: number) => {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
const React = require('react');
|
||||
import * as React from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import { themeStyle } from './global-style';
|
||||
import { TextInput, TextInputProps, StyleSheet } from 'react-native';
|
||||
|
@@ -1,4 +1,4 @@
|
||||
const React = require('react');
|
||||
import * as React from 'react';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { View, Dimensions, Alert, Button } from 'react-native';
|
||||
|
@@ -56,7 +56,7 @@ const FloatingActionButton = (props: ActionButtonProps) => {
|
||||
if (open) onMenuToggled();
|
||||
}, [open, onMenuToggled]);
|
||||
|
||||
const mainButtonRef = useRef<View>();
|
||||
const mainButtonRef = useRef<View>(null);
|
||||
|
||||
const closedIcon = useIcon(props.mainButton?.icon ?? 'add');
|
||||
const openIcon = useIcon('close');
|
||||
|
@@ -99,7 +99,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const PluginRunnerWebViewComponent: React.FC<Props> = props => {
|
||||
const webviewRef = useRef<WebViewControl>();
|
||||
const webviewRef = useRef<WebViewControl>(null);
|
||||
|
||||
const [webviewLoaded, setLoaded] = useState(false);
|
||||
const [webviewReloadCounter, setWebviewReloadCounter] = useState(0);
|
||||
|
@@ -9,7 +9,7 @@ import usePlugin from '@joplin/lib/hooks/usePlugin';
|
||||
const usePluginItem = (id: string, pluginSettings: PluginSettings, initialItem: PluginItem|null): PluginItem => {
|
||||
const plugin = usePlugin(id);
|
||||
|
||||
const lastManifest = useRef<PluginManifest>();
|
||||
const lastManifest = useRef<PluginManifest|null>(null);
|
||||
if (plugin) {
|
||||
lastManifest.current = plugin.manifest;
|
||||
} else if (!lastManifest.current) {
|
||||
|
@@ -20,7 +20,7 @@ import BackButtonService from '../../../services/BackButtonService';
|
||||
import NavService, { OnNavigateCallback as OnNavigateCallback } from '@joplin/lib/services/NavService';
|
||||
import { ModelType } from '@joplin/lib/BaseModel';
|
||||
import FloatingActionButton from '../../buttons/FloatingActionButton';
|
||||
const { fileExtension, safeFileExtension } = require('@joplin/lib/path-utils');
|
||||
import { fileExtension, safeFileExtension } from '@joplin/lib/path-utils';
|
||||
import * as mimeUtils from '@joplin/lib/mime-utils';
|
||||
import ScreenHeader, { MenuOptionType } from '../../ScreenHeader';
|
||||
import NoteTagsDialog from '../NoteTagsDialog';
|
||||
@@ -1561,7 +1561,6 @@ class NoteScreenComponent extends BaseScreenComponent<ComponentProps, State> imp
|
||||
<TextInput
|
||||
autoCapitalize="sentences"
|
||||
style={this.styles().bodyTextInput}
|
||||
ref="noteBodyTextField"
|
||||
multiline={true}
|
||||
value={note.body}
|
||||
onChangeText={this.onPlainEditorTextChange}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import useSyncTargetUpgrade from '@joplin/lib/services/synchronizer/gui/useSyncTargetUpgrade';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
const { View, Text, ScrollView } = require('react-native');
|
||||
import { View, Text, ScrollView, TextStyle } from 'react-native';
|
||||
|
||||
const { connect } = require('react-redux');
|
||||
import { themeStyle } from '../global-style';
|
||||
@@ -14,7 +14,7 @@ function UpgradeSyncTargetScreen(props: any) {
|
||||
const theme = themeStyle(props.themeId);
|
||||
|
||||
const lineStyle = { ...theme.normalText, marginBottom: 20 };
|
||||
const stackTraceStyle = { ...theme.normalText, flexWrap: 'nowrap', fontSize: theme.fontSize * 0.5, color: theme.colorFaded };
|
||||
const stackTraceStyle: TextStyle = { ...theme.normalText, flexWrap: 'nowrap', fontSize: theme.fontSize * 0.5, color: theme.colorFaded };
|
||||
const headerStyle = { ...theme.headerStyle, marginBottom: 20 };
|
||||
|
||||
function renderUpgradeError() {
|
||||
|
@@ -109,7 +109,7 @@ const useAudioRecorder = (onFileSaved: OnFileSavedCallback, onDismiss: ()=> void
|
||||
const [error, setError] = useState('');
|
||||
const [duration, setDuration] = useState(0);
|
||||
|
||||
const recordingRef = useRef<Audio.Recording|null>();
|
||||
const recordingRef = useRef<Audio.Recording|null>(null);
|
||||
const onStartRecording = useCallback(async () => {
|
||||
try {
|
||||
setRecordingState(RecorderState.Loading);
|
||||
|
@@ -1,4 +1,4 @@
|
||||
const React = require('react');
|
||||
import * as React from 'react';
|
||||
import shim from '@joplin/lib/shim';
|
||||
shim.setReact(React);
|
||||
|
||||
@@ -17,7 +17,7 @@ import UpgradeSyncTargetScreen from './components/screens/UpgradeSyncTargetScree
|
||||
import Setting, { AppType, Env } from '@joplin/lib/models/Setting';
|
||||
import PoorManIntervals from '@joplin/lib/PoorManIntervals';
|
||||
import reducer, { NotesParent, parseNotesParent, serializeNotesParent } from '@joplin/lib/reducer';
|
||||
import ShareExtension from './utils/ShareExtension';
|
||||
import ShareExtension, { UnsubscribeShareListener } from './utils/ShareExtension';
|
||||
import handleShared from './utils/shareHandler';
|
||||
import uuid from '@joplin/lib/uuid';
|
||||
import { loadKeychainServiceAndSettings } from '@joplin/lib/services/SettingUtils';
|
||||
@@ -30,14 +30,14 @@ const VersionInfo = require('react-native-version-info').default;
|
||||
import { Keyboard, BackHandler, Animated, StatusBar, Platform, Dimensions } from 'react-native';
|
||||
import { AppState as RNAppState, EmitterSubscription, View, Text, Linking, NativeEventSubscription, Appearance, ActivityIndicator } from 'react-native';
|
||||
import getResponsiveValue from './components/getResponsiveValue';
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
import NetInfo, { NetInfoSubscription } from '@react-native-community/netinfo';
|
||||
const DropdownAlert = require('react-native-dropdownalert').default;
|
||||
const AlarmServiceDriver = require('./services/AlarmServiceDriver').default;
|
||||
const SafeAreaView = require('./components/SafeAreaView');
|
||||
const { connect, Provider } = require('react-redux');
|
||||
import fastDeepEqual = require('fast-deep-equal');
|
||||
import { Provider as PaperProvider, MD3DarkTheme, MD3LightTheme } from 'react-native-paper';
|
||||
import BackButtonService from './services/BackButtonService';
|
||||
import BackButtonService, { BackButtonHandler } from './services/BackButtonService';
|
||||
import NavService from '@joplin/lib/services/NavService';
|
||||
import { createStore, applyMiddleware, Dispatch } from 'redux';
|
||||
import reduxSharedMiddleware from '@joplin/lib/components/shared/reduxSharedMiddleware';
|
||||
@@ -68,9 +68,9 @@ import DropboxLoginScreen from './components/screens/dropbox-login.js';
|
||||
import { MenuProvider } from 'react-native-popup-menu';
|
||||
import SideMenu, { SideMenuPosition } from './components/SideMenu';
|
||||
import SideMenuContent from './components/side-menu-content';
|
||||
import SideMenuContentNote from './components/SideMenuContentNote';
|
||||
import SideMenuContentNote, { SideMenuContentOptions } from './components/SideMenuContentNote';
|
||||
import { reg } from '@joplin/lib/registry';
|
||||
const { defaultState } = require('@joplin/lib/reducer');
|
||||
import { defaultState } from '@joplin/lib/reducer';
|
||||
import FileApiDriverLocal from '@joplin/lib/file-api-driver-local';
|
||||
import ResourceFetcher from '@joplin/lib/services/ResourceFetcher';
|
||||
import SearchEngine from '@joplin/lib/services/search/SearchEngine';
|
||||
@@ -853,7 +853,27 @@ async function initialize(dispatch: Dispatch) {
|
||||
reg.logger().info('Application initialized');
|
||||
}
|
||||
|
||||
class AppComponent extends React.Component {
|
||||
interface AppComponentProps {
|
||||
dispatch: Dispatch;
|
||||
themeId: number;
|
||||
biometricsDone: boolean;
|
||||
routeName: string;
|
||||
selectedFolderId: string;
|
||||
appState: string;
|
||||
noteSideMenuOptions: SideMenuContentOptions;
|
||||
disableSideMenuGestures: boolean;
|
||||
historyCanGoBack: boolean;
|
||||
showSideMenu: boolean;
|
||||
noteSelectionEnabled: boolean;
|
||||
}
|
||||
|
||||
interface AppComponentState {
|
||||
sideMenuWidth: number;
|
||||
sensorInfo: SensorInfo;
|
||||
sideMenuContentOpacity: Animated.Value;
|
||||
}
|
||||
|
||||
class AppComponent extends React.Component<AppComponentProps, AppComponentState> {
|
||||
|
||||
private urlOpenListener_: EmitterSubscription|null = null;
|
||||
private appStateChangeListener_: NativeEventSubscription|null = null;
|
||||
@@ -864,8 +884,18 @@ class AppComponent extends React.Component {
|
||||
private dropdownAlert_ = (_data: any) => new Promise<any>(res => res);
|
||||
private callbackUrl: string|null = null;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
private lastSyncStarted_ = false;
|
||||
private quickActionShortcutListener_: EmitterSubscription|undefined;
|
||||
private unsubscribeScreenWidthChangeHandler_: EmitterSubscription|undefined;
|
||||
private unsubscribeNetInfoHandler_: NetInfoSubscription|undefined;
|
||||
private unsubscribeNewShareListener_: UnsubscribeShareListener|undefined;
|
||||
private onAppStateChange_: ()=> void;
|
||||
private backButtonHandler_: BackButtonHandler;
|
||||
private handleNewShare_: ()=> void;
|
||||
private handleOpenURL_: (event: unknown)=> void;
|
||||
|
||||
public constructor(props: AppComponentProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
sideMenuContentOpacity: new Animated.Value(0),
|
||||
@@ -1390,8 +1420,7 @@ class AppComponent extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
const mapStateToProps = (state: any) => {
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
return {
|
||||
historyCanGoBack: state.historyCanGoBack,
|
||||
showSideMenu: state.showSideMenu,
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { BackHandler } from 'react-native';
|
||||
|
||||
type BackButtonHandler = ()=> boolean|Promise<boolean>;
|
||||
export type BackButtonHandler = ()=> boolean|Promise<boolean>;
|
||||
|
||||
export default class BackButtonService {
|
||||
private static handlers_: BackButtonHandler[] = [];
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import { NativeEventEmitter } from 'react-native';
|
||||
|
||||
const { NativeModules, Platform } = require('react-native');
|
||||
import { NativeModules, Platform } from 'react-native';
|
||||
|
||||
export interface SharedData {
|
||||
title?: string;
|
||||
@@ -8,26 +7,36 @@ export interface SharedData {
|
||||
resources?: string[];
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
type ShareListener = (event: any)=> void;
|
||||
export type UnsubscribeShareListener = ()=> void;
|
||||
type ShareExtensionType = {
|
||||
data: ()=> Promise<SharedData>;
|
||||
close: ()=> void;
|
||||
shareURL: ()=> string;
|
||||
addShareListener: (listener: ShareListener)=> UnsubscribeShareListener|undefined;
|
||||
};
|
||||
|
||||
|
||||
let eventEmitter: NativeEventEmitter | undefined;
|
||||
|
||||
const ShareExtension = (NativeModules.ShareExtension) ?
|
||||
const ShareExtension: ShareExtensionType = (NativeModules.ShareExtension) ?
|
||||
{
|
||||
data: () => NativeModules.ShareExtension.data(),
|
||||
close: () => NativeModules.ShareExtension.close(),
|
||||
shareURL: (Platform.OS === 'ios') ? NativeModules.ShareExtension.getConstants().SHARE_EXTENSION_SHARE_URL : '',
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||
addShareListener: (Platform.OS === 'android') ? ((handler: (event: any)=> void) => {
|
||||
addShareListener: (Platform.OS === 'android') ? ((handler) => {
|
||||
if (!eventEmitter) {
|
||||
eventEmitter = new NativeEventEmitter(NativeModules.ShareExtension);
|
||||
}
|
||||
return eventEmitter.addListener('new_share_intent', handler).remove;
|
||||
}) : (() => {}),
|
||||
}) : (() => undefined),
|
||||
} :
|
||||
{
|
||||
data: () => {},
|
||||
close: () => {},
|
||||
shareURL: '',
|
||||
addShareListener: () => {},
|
||||
addShareListener: () => undefined,
|
||||
};
|
||||
|
||||
export default ShareExtension;
|
||||
|
@@ -4,9 +4,9 @@ import shim from '@joplin/lib/shim';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import checkPermissions from './checkPermissions.js';
|
||||
import NavService from '@joplin/lib/services/NavService';
|
||||
const { ToastAndroid } = require('react-native');
|
||||
const { PermissionsAndroid } = require('react-native');
|
||||
const { Platform } = require('react-native');
|
||||
import { ToastAndroid } from 'react-native';
|
||||
import { PermissionsAndroid } from 'react-native';
|
||||
import { Platform } from 'react-native';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||
export default async (sharedData: SharedData, folderId: string, dispatch: Function) => {
|
||||
|
Reference in New Issue
Block a user