From 92c24c2129407f36f04c979c16665c9352767927 Mon Sep 17 00:00:00 2001 From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com> Date: Sat, 27 Aug 2022 05:36:59 -0700 Subject: [PATCH] Chore: Migrate mobile Dropdown, ScreenHeader to TypeScript (#6763) --- .eslintignore | 6 + .gitignore | 6 + .../components/{Dropdown.js => Dropdown.tsx} | 73 +++++-- .../{screen-header.js => ScreenHeader.tsx} | 202 ++++++++++++------ .../components/screens/ConfigScreen.tsx | 4 +- .../app-mobile/components/screens/Note.tsx | 2 +- .../screens/UpgradeSyncTargetScreen.tsx | 2 +- .../components/screens/dropbox-login.js | 2 +- .../components/screens/encryption-config.tsx | 2 +- .../app-mobile/components/screens/folder.js | 2 +- packages/app-mobile/components/screens/log.js | 2 +- .../app-mobile/components/screens/notes.js | 2 +- .../components/screens/onedrive-login.js | 2 +- .../app-mobile/components/screens/search.js | 2 +- .../app-mobile/components/screens/status.js | 2 +- .../app-mobile/components/screens/tags.js | 2 +- packages/app-mobile/package.json | 1 + packages/lib/models/Folder.ts | 4 +- packages/lib/reducer.ts | 1 + yarn.lock | 13 ++ 20 files changed, 229 insertions(+), 103 deletions(-) rename packages/app-mobile/components/{Dropdown.js => Dropdown.tsx} (72%) rename packages/app-mobile/components/{screen-header.js => ScreenHeader.tsx} (77%) diff --git a/.eslintignore b/.eslintignore index 1981ec6de..16825e037 100644 --- a/.eslintignore +++ b/.eslintignore @@ -842,6 +842,9 @@ packages/app-mobile/components/BackButtonDialogBox.js.map packages/app-mobile/components/CameraView.d.ts packages/app-mobile/components/CameraView.js packages/app-mobile/components/CameraView.js.map +packages/app-mobile/components/Dropdown.d.ts +packages/app-mobile/components/Dropdown.js +packages/app-mobile/components/Dropdown.js.map packages/app-mobile/components/CustomButton.d.ts packages/app-mobile/components/CustomButton.js packages/app-mobile/components/CustomButton.js.map @@ -917,6 +920,9 @@ 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/ScreenHeader.d.ts +packages/app-mobile/components/ScreenHeader.js +packages/app-mobile/components/ScreenHeader.js.map packages/app-mobile/components/SelectDateTimeDialog.d.ts packages/app-mobile/components/SelectDateTimeDialog.js packages/app-mobile/components/SelectDateTimeDialog.js.map diff --git a/.gitignore b/.gitignore index 8140c475f..3122a8dab 100644 --- a/.gitignore +++ b/.gitignore @@ -834,6 +834,9 @@ packages/app-mobile/components/CameraView.js.map packages/app-mobile/components/CustomButton.d.ts packages/app-mobile/components/CustomButton.js packages/app-mobile/components/CustomButton.js.map +packages/app-mobile/components/Dropdown.d.ts +packages/app-mobile/components/Dropdown.js +packages/app-mobile/components/Dropdown.js.map packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.d.ts packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js packages/app-mobile/components/NoteBodyViewer/NoteBodyViewer.js.map @@ -906,6 +909,9 @@ 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/ScreenHeader.d.ts +packages/app-mobile/components/ScreenHeader.js +packages/app-mobile/components/ScreenHeader.js.map packages/app-mobile/components/SelectDateTimeDialog.d.ts packages/app-mobile/components/SelectDateTimeDialog.js packages/app-mobile/components/SelectDateTimeDialog.js.map diff --git a/packages/app-mobile/components/Dropdown.js b/packages/app-mobile/components/Dropdown.tsx similarity index 72% rename from packages/app-mobile/components/Dropdown.js rename to packages/app-mobile/components/Dropdown.tsx index 5413692a8..464294c4a 100644 --- a/packages/app-mobile/components/Dropdown.js +++ b/packages/app-mobile/components/Dropdown.tsx @@ -1,31 +1,60 @@ const React = require('react'); -const { TouchableOpacity, TouchableWithoutFeedback, Dimensions, Text, Modal, View } = require('react-native'); +import { TouchableOpacity, TouchableWithoutFeedback, Dimensions, Text, Modal, View, LayoutRectangle, ViewStyle, TextStyle } from 'react-native'; +import { Component } from 'react'; const { ItemList } = require('./ItemList.js'); -class Dropdown extends React.Component { - constructor() { - super(); +type ValueType = string; +export interface DropdownListItem { + label: string; + value: ValueType; +} - this.headerRef_ = null; - } +export type OnValueChangedListener = (newValue: ValueType)=> void; - UNSAFE_componentWillMount() { - this.setState({ +interface DropdownProps { + listItemStyle?: ViewStyle; + itemListStyle?: ViewStyle; + itemWrapperStyle?: ViewStyle; + headerWrapperStyle?: ViewStyle; + headerStyle?: TextStyle; + itemStyle?: TextStyle; + disabled?: boolean; + + labelTransform?: 'trim'; + items: DropdownListItem[]; + + selectedValue: ValueType|null; + onValueChange?: OnValueChangedListener; +} + +interface DropdownState { + headerSize: LayoutRectangle; + listVisible: boolean; +} + +class Dropdown extends Component { + private headerRef: TouchableOpacity; + + public constructor(props: DropdownProps) { + super(props); + + this.headerRef = null; + this.state = { headerSize: { x: 0, y: 0, width: 0, height: 0 }, listVisible: false, - }); + }; } - updateHeaderCoordinates() { + private updateHeaderCoordinates() { // https://stackoverflow.com/questions/30096038/react-native-getting-the-position-of-an-element - this.headerRef_.measure((fx, fy, width, height, px, py) => { + this.headerRef.measure((_fx, _fy, width, height, px, py) => { this.setState({ headerSize: { x: px, y: py, width: width, height: height }, }); }); } - render() { + public render() { const items = this.props.items; const itemHeight = 60; const windowHeight = Dimensions.get('window').height - 50; @@ -84,23 +113,26 @@ class Dropdown extends React.Component { } } - if (this.props.labelTransform && this.props.labelTransform === 'trim') headerLabel = headerLabel.trim(); + if (this.props.labelTransform && this.props.labelTransform === 'trim') { + headerLabel = headerLabel.trim(); + } const closeList = () => { this.setState({ listVisible: false }); }; - const itemRenderer = item => { + const itemRenderer = (item: DropdownListItem) => { + const key = item.value.toString(); return ( { closeList(); if (this.props.onValueChange) this.props.onValueChange(item.value); }} > - + {item.label} @@ -111,7 +143,7 @@ class Dropdown extends React.Component { (this.headerRef_ = ref)} + ref={ref => (this.headerRef = ref)} disabled={this.props.disabled} onPress={() => { this.updateHeaderCoordinates(); @@ -141,9 +173,7 @@ class Dropdown extends React.Component { style={itemListStyle} items={this.props.items} itemHeight={itemHeight} - itemRenderer={item => { - return itemRenderer(item); - }} + itemRenderer={itemRenderer} /> @@ -154,4 +184,5 @@ class Dropdown extends React.Component { } } -module.exports = { Dropdown }; +export default Dropdown; +export { Dropdown }; diff --git a/packages/app-mobile/components/screen-header.js b/packages/app-mobile/components/ScreenHeader.tsx similarity index 77% rename from packages/app-mobile/components/screen-header.js rename to packages/app-mobile/components/ScreenHeader.tsx index bab6cbe4f..5a40289b9 100644 --- a/packages/app-mobile/components/screen-header.js +++ b/packages/app-mobile/components/ScreenHeader.tsx @@ -1,21 +1,24 @@ const React = require('react'); -const { connect } = require('react-redux'); -const { View, Text, StyleSheet, TouchableOpacity, Image, ScrollView, Dimensions } = require('react-native'); +import { connect } from 'react-redux'; +import { PureComponent, Component } from 'react'; +import { View, Text, StyleSheet, TouchableOpacity, Image, ScrollView, Dimensions, ViewStyle } from 'react-native'; const Icon = require('react-native-vector-icons/Ionicons').default; const { BackButtonService } = require('../services/back-button.js'); -const NavService = require('@joplin/lib/services/NavService').default; -const { Menu, MenuOptions, MenuOption, MenuTrigger } = require('react-native-popup-menu'); -const { _ } = require('@joplin/lib/locale'); -const Setting = require('@joplin/lib/models/Setting').default; -const Note = require('@joplin/lib/models/Note').default; -const Folder = require('@joplin/lib/models/Folder').default; +import NavService from '@joplin/lib/services/NavService'; +import { Menu, MenuOptions, MenuOption, MenuTrigger } from 'react-native-popup-menu'; +import { _ } from '@joplin/lib/locale'; +import Setting from '@joplin/lib/models/Setting'; +import Note from '@joplin/lib/models/Note'; +import Folder, { FolderEntityWithChildren } from '@joplin/lib/models/Folder'; const { themeStyle } = require('./global-style.js'); -const { Dropdown } = require('./Dropdown.js'); +import Dropdown, { DropdownListItem, OnValueChangedListener } from './Dropdown'; const { dialogs } = require('../utils/dialogs.js'); const DialogBox = require('react-native-dialogbox').default; -const { localSyncInfoFromState } = require('@joplin/lib/services/synchronizer/syncInfoUtils'); -const { showMissingMasterKeyMessage } = require('@joplin/lib/services/e2ee/utils'); +import { localSyncInfoFromState } from '@joplin/lib/services/synchronizer/syncInfoUtils'; +import { showMissingMasterKeyMessage } from '@joplin/lib/services/e2ee/utils'; +import { FolderEntity } from '@joplin/lib/services/database/types'; +import { State } from '@joplin/lib/reducer'; import CustomButton from './CustomButton'; Icon.loadFont(); @@ -26,20 +29,78 @@ Icon.loadFont(); // default height. const PADDING_V = 10; -class ScreenHeaderComponent extends React.PureComponent { - constructor() { - super(); - this.styles_ = {}; +type OnSelectCallbackType=()=> void; +type OnPressCallback=()=> void; +interface NavButtonPressEvent { + // Name of the screen to navigate to + screen: string; +} + +interface MenuOptionType { + onPress: OnPressCallback; + isDivider?: boolean; + title: string; +} + +type DispatchCommandType=(event: { type: string })=> void; +interface ScreenHeaderProps { + selectedNoteIds: string[]; + noteSelectionEnabled: boolean; + parentComponent: Component; + showUndoButton: boolean; + undoButtonDisabled?: boolean; + showRedoButton: boolean; + menuOptions: MenuOptionType[]; + title?: string|null; + folders: FolderEntity[]; + folderPickerOptions?: { + enabled: boolean; + selectedFolderId: string; + onValueChange: OnValueChangedListener; + mustSelect?: boolean; + }; + + dispatch: DispatchCommandType; + onUndoButtonPress: OnPressCallback; + onRedoButtonPress: OnPressCallback; + onSaveButtonPress: OnPressCallback; + sortButton_press?: OnPressCallback; + + showSideMenuButton?: boolean; + showSearchButton?: boolean; + showContextMenuButton?: boolean; + showBackButton?: boolean; + + saveButtonDisabled?: boolean; + showSaveButton?: boolean; + + historyCanGoBack?: boolean; + showMissingMasterKeyMessage?: boolean; + hasDisabledSyncItems?: boolean; + shouldUpgradeSyncTarget?: boolean; + showShouldUpgradeSyncTargetMessage?: boolean; + +} + +interface ScreenHeaderState { +} + +class ScreenHeaderComponent extends PureComponent { + private cachedStyles: any; + public dialogbox?: typeof DialogBox; + public constructor(props: ScreenHeaderProps) { + super(props); + this.cachedStyles = {}; } - styles() { + private styles() { const themeId = Setting.value('theme'); - if (this.styles_[themeId]) return this.styles_[themeId]; - this.styles_ = {}; + if (this.cachedStyles[themeId]) return this.cachedStyles[themeId]; + this.cachedStyles = {}; const theme = themeStyle(themeId); - const styleObject = { + const styleObject: any = { container: { flexDirection: 'column', backgroundColor: theme.backgroundColor2, @@ -148,15 +209,15 @@ class ScreenHeaderComponent extends React.PureComponent { styleObject.saveButtonDisabled = Object.assign({}, styleObject.saveButton, { opacity: theme.disabledOpacity }); styleObject.iconButtonDisabled = Object.assign({}, styleObject.iconButton, { opacity: theme.disabledOpacity }); - this.styles_[themeId] = StyleSheet.create(styleObject); - return this.styles_[themeId]; + this.cachedStyles[themeId] = StyleSheet.create(styleObject); + return this.cachedStyles[themeId]; } - sideMenuButton_press() { + private sideMenuButton_press() { this.props.dispatch({ type: 'SIDE_MENU_TOGGLE' }); } - async backButton_press() { + private async backButton_press() { if (this.props.noteSelectionEnabled) { this.props.dispatch({ type: 'NOTE_SELECTION_END' }); } else { @@ -164,15 +225,15 @@ class ScreenHeaderComponent extends React.PureComponent { } } - selectAllButton_press() { + private selectAllButton_press() { this.props.dispatch({ type: 'NOTE_SELECT_ALL_TOGGLE' }); } - searchButton_press() { - NavService.go('Search'); + private searchButton_press() { + void NavService.go('Search'); } - async duplicateButton_press() { + private async duplicateButton_press() { const noteIds = this.props.selectedNoteIds; // Duplicate all selected notes. ensureUniqueTitle is set to true to use the @@ -182,7 +243,7 @@ class ScreenHeaderComponent extends React.PureComponent { this.props.dispatch({ type: 'NOTE_SELECTION_END' }); } - async deleteButton_press() { + private async deleteButton_press() { // Dialog needs to be displayed as a child of the parent component, otherwise // it won't be visible within the header component. const noteIds = this.props.selectedNoteIds; @@ -197,25 +258,17 @@ class ScreenHeaderComponent extends React.PureComponent { await Note.batchDelete(noteIds); } - menu_select(value) { + private menu_select(value: OnSelectCallbackType) { if (typeof value === 'function') { value(); } } - log_press() { - NavService.go('Log'); + private warningBox_press(event: NavButtonPressEvent) { + void NavService.go(event.screen); } - status_press() { - NavService.go('Status'); - } - - warningBox_press(event) { - NavService.go(event.screen); - } - - renderWarningBox(screen, message) { + private renderWarningBox(screen: string, message: string) { return ( this.warningBox_press({ screen: screen })} activeOpacity={0.8}> {message} @@ -223,9 +276,9 @@ class ScreenHeaderComponent extends React.PureComponent { ); } - render() { + public render() { const themeId = Setting.value('theme'); - function sideMenuButton(styles, onPress) { + function sideMenuButton(styles: any, onPress: OnPressCallback) { return ( : ; @@ -278,7 +333,14 @@ class ScreenHeaderComponent extends React.PureComponent { ); } - const renderTopButton = (options) => { + interface TopButtonOptions { + visible: boolean; + iconName: string; + disabled?: boolean; + description: string; + onPress: OnPressCallback; + } + const renderTopButton = (options: TopButtonOptions) => { if (!options.visible) return null; const icon = ; @@ -317,7 +379,7 @@ class ScreenHeaderComponent extends React.PureComponent { }); }; - function selectAllButton(styles, onPress) { + function selectAllButton(styles: any, onPress: OnPressCallback) { return ( { + const createTitleComponent = (disabled: boolean) => { + const themeId = Setting.value('theme'); const theme = themeStyle(themeId); const folderPickerOptions = this.props.folderPickerOptions; if (folderPickerOptions && folderPickerOptions.enabled) { - const addFolderChildren = (folders, pickerItems, indent) => { + const addFolderChildren = ( + folders: FolderEntityWithChildren[], pickerItems: DropdownListItem[], indent: number + ) => { folders.sort((a, b) => { const aTitle = a && a.title ? a.title : ''; const bTitle = b && b.title ? b.title : ''; @@ -453,7 +518,7 @@ class ScreenHeaderComponent extends React.PureComponent { return pickerItems; }; - const titlePickerItems = mustSelect => { + const titlePickerItems = (mustSelect: boolean) => { const folders = this.props.folders.filter(f => f.id !== Folder.conflictFolderId()); let output = []; if (mustSelect) output.push({ label: _('Move to notebook...'), value: null }); @@ -465,7 +530,6 @@ class ScreenHeaderComponent extends React.PureComponent { return ( { + onValueChange={async (folderId) => { // If onValueChange is specified, use this as a callback, otherwise do the default // which is to take the selectedNoteIds from the state and move them to the // chosen folder. if (folderPickerOptions.onValueChange) { - folderPickerOptions.onValueChange(folderId, itemIndex); + folderPickerOptions.onValueChange(folderId); return; } @@ -527,7 +591,7 @@ class ScreenHeaderComponent extends React.PureComponent { let backButtonDisabled = !this.props.historyCanGoBack; if (this.props.noteSelectionEnabled) backButtonDisabled = false; - const headerItemDisabled = !this.props.selectedNoteIds.length > 0; + const headerItemDisabled = !(this.props.selectedNoteIds.length > 0); const titleComp = createTitleComponent(headerItemDisabled); const sideMenuComp = !showSideMenuButton ? null : sideMenuButton(this.styles(), () => this.sideMenuButton_press()); @@ -539,7 +603,10 @@ class ScreenHeaderComponent extends React.PureComponent { const sortButtonComp = !this.props.noteSelectionEnabled && this.props.sortButton_press ? sortButton(this.styles(), () => this.props.sortButton_press()) : null; const windowHeight = Dimensions.get('window').height - 50; - const contextMenuStyle = { paddingTop: PADDING_V, paddingBottom: PADDING_V }; + const contextMenuStyle: ViewStyle = { + paddingTop: PADDING_V, + paddingBottom: PADDING_V, + }; // HACK: if this button is removed during selection mode, the header layout is broken, so for now just make it 1 pixel large (normally it should be hidden) if (this.props.noteSelectionEnabled) contextMenuStyle.width = 1; @@ -561,8 +628,8 @@ class ScreenHeaderComponent extends React.PureComponent { {sideMenuComp} {backButtonComp} - {renderUndoButton(this.styles())} - {renderRedoButton(this.styles())} + {renderUndoButton()} + {renderRedoButton()} {saveButton( this.styles(), () => { @@ -581,20 +648,20 @@ class ScreenHeaderComponent extends React.PureComponent { {warningComps} { + ref={(dialogbox: typeof DialogBox) => { this.dialogbox = dialogbox; }} /> ); } + + public static defaultProps: Partial ={ + menuOptions: [], + }; } -ScreenHeaderComponent.defaultProps = { - menuOptions: [], -}; - -const ScreenHeader = connect(state => { +const ScreenHeader = connect((state: State) => { const syncInfo = localSyncInfoFromState(state); return { @@ -610,4 +677,5 @@ const ScreenHeader = connect(state => { }; })(ScreenHeaderComponent); -module.exports = { ScreenHeader }; +export default ScreenHeader; +export { ScreenHeader }; diff --git a/packages/app-mobile/components/screens/ConfigScreen.tsx b/packages/app-mobile/components/screens/ConfigScreen.tsx index 47bffc457..fc01d3a0f 100644 --- a/packages/app-mobile/components/screens/ConfigScreen.tsx +++ b/packages/app-mobile/components/screens/ConfigScreen.tsx @@ -14,7 +14,7 @@ import { reg } from '@joplin/lib/registry'; import { State } from '@joplin/lib/reducer'; const VersionInfo = require('react-native-version-info').default; const { connect } = require('react-redux'); -const { ScreenHeader } = require('../screen-header.js'); +import ScreenHeader from '../ScreenHeader'; const { _ } = require('@joplin/lib/locale'); const { BaseScreenComponent } = require('../base-screen.js'); const { Dropdown } = require('../Dropdown.js'); @@ -461,7 +461,7 @@ class ConfigScreenComponent extends BaseScreenComponent { color: theme.color, fontSize: theme.fontSize, }} - onValueChange={(itemValue: any) => { + onValueChange={(itemValue: string) => { updateSettingValue(key, itemValue); }} /> diff --git a/packages/app-mobile/components/screens/Note.tsx b/packages/app-mobile/components/screens/Note.tsx index 1ee7aed10..f859ad32e 100644 --- a/packages/app-mobile/components/screens/Note.tsx +++ b/packages/app-mobile/components/screens/Note.tsx @@ -26,7 +26,7 @@ import BaseModel from '@joplin/lib/BaseModel'; const { ActionButton } = require('../action-button.js'); const { fileExtension, safeFileExtension } = require('@joplin/lib/path-utils'); const mimeUtils = require('@joplin/lib/mime-utils.js').mime; -const { ScreenHeader } = require('../screen-header.js'); +import ScreenHeader from '../ScreenHeader'; const NoteTagsDialog = require('./NoteTagsDialog'); import time from '@joplin/lib/time'; const { Checkbox } = require('../checkbox.js'); diff --git a/packages/app-mobile/components/screens/UpgradeSyncTargetScreen.tsx b/packages/app-mobile/components/screens/UpgradeSyncTargetScreen.tsx index df133e76c..c2a6ab5f3 100644 --- a/packages/app-mobile/components/screens/UpgradeSyncTargetScreen.tsx +++ b/packages/app-mobile/components/screens/UpgradeSyncTargetScreen.tsx @@ -5,7 +5,7 @@ const { View, Text, ScrollView } = require('react-native'); const { connect } = require('react-redux'); const { themeStyle } = require('../global-style.js'); -const { ScreenHeader } = require('../screen-header.js'); +import ScreenHeader from '../ScreenHeader'; function UpgradeSyncTargetScreen(props: any) { const upgradeResult = useSyncTargetUpgrade(); diff --git a/packages/app-mobile/components/screens/dropbox-login.js b/packages/app-mobile/components/screens/dropbox-login.js index d3204daa7..6d861bc8e 100644 --- a/packages/app-mobile/components/screens/dropbox-login.js +++ b/packages/app-mobile/components/screens/dropbox-login.js @@ -2,7 +2,7 @@ const React = require('react'); const { View, Button, Text, TextInput, TouchableOpacity, StyleSheet, ScrollView } = require('react-native'); const { connect } = require('react-redux'); -const { ScreenHeader } = require('../screen-header.js'); +const { ScreenHeader } = require('../ScreenHeader'); const { _ } = require('@joplin/lib/locale'); const { BaseScreenComponent } = require('../base-screen.js'); const DialogBox = require('react-native-dialogbox').default; diff --git a/packages/app-mobile/components/screens/encryption-config.tsx b/packages/app-mobile/components/screens/encryption-config.tsx index 6e885535b..7c9e4603a 100644 --- a/packages/app-mobile/components/screens/encryption-config.tsx +++ b/packages/app-mobile/components/screens/encryption-config.tsx @@ -1,7 +1,7 @@ const React = require('react'); const { TextInput, TouchableOpacity, Linking, View, StyleSheet, Text, Button, ScrollView } = require('react-native'); const { connect } = require('react-redux'); -const { ScreenHeader } = require('../screen-header.js'); +import ScreenHeader from '../ScreenHeader'; const { themeStyle } = require('../global-style.js'); const DialogBox = require('react-native-dialogbox').default; const { dialogs } = require('../../utils/dialogs.js'); diff --git a/packages/app-mobile/components/screens/folder.js b/packages/app-mobile/components/screens/folder.js index 2026afcea..38c8c9710 100644 --- a/packages/app-mobile/components/screens/folder.js +++ b/packages/app-mobile/components/screens/folder.js @@ -4,7 +4,7 @@ const { View, TextInput, StyleSheet } = require('react-native'); const { connect } = require('react-redux'); const Folder = require('@joplin/lib/models/Folder').default; const BaseModel = require('@joplin/lib/BaseModel').default; -const { ScreenHeader } = require('../screen-header.js'); +const { ScreenHeader } = require('../ScreenHeader'); const { BaseScreenComponent } = require('../base-screen.js'); const { dialogs } = require('../../utils/dialogs.js'); const { themeStyle } = require('../global-style.js'); diff --git a/packages/app-mobile/components/screens/log.js b/packages/app-mobile/components/screens/log.js index 0cd92b7ec..b7cc3377a 100644 --- a/packages/app-mobile/components/screens/log.js +++ b/packages/app-mobile/components/screens/log.js @@ -3,7 +3,7 @@ const React = require('react'); const { FlatList, View, Text, Button, StyleSheet, Platform } = require('react-native'); const { connect } = require('react-redux'); const { reg } = require('@joplin/lib/registry.js'); -const { ScreenHeader } = require('../screen-header.js'); +const { ScreenHeader } = require('../ScreenHeader'); const time = require('@joplin/lib/time').default; const { themeStyle } = require('../global-style.js'); const Logger = require('@joplin/lib/Logger').default; diff --git a/packages/app-mobile/components/screens/notes.js b/packages/app-mobile/components/screens/notes.js index b513d498b..e39500858 100644 --- a/packages/app-mobile/components/screens/notes.js +++ b/packages/app-mobile/components/screens/notes.js @@ -9,7 +9,7 @@ const Tag = require('@joplin/lib/models/Tag').default; const Note = require('@joplin/lib/models/Note').default; const Setting = require('@joplin/lib/models/Setting').default; const { themeStyle } = require('../global-style.js'); -const { ScreenHeader } = require('../screen-header.js'); +const { ScreenHeader } = require('../ScreenHeader'); const { _ } = require('@joplin/lib/locale'); const { ActionButton } = require('../action-button.js'); const { dialogs } = require('../../utils/dialogs.js'); diff --git a/packages/app-mobile/components/screens/onedrive-login.js b/packages/app-mobile/components/screens/onedrive-login.js index 3259f6ae1..6d6608f60 100644 --- a/packages/app-mobile/components/screens/onedrive-login.js +++ b/packages/app-mobile/components/screens/onedrive-login.js @@ -4,7 +4,7 @@ const { View } = require('react-native'); const { Button } = require('react-native'); const { WebView } = require('react-native-webview'); const { connect } = require('react-redux'); -const { ScreenHeader } = require('../screen-header.js'); +const { ScreenHeader } = require('../ScreenHeader'); const { reg } = require('@joplin/lib/registry.js'); const { _ } = require('@joplin/lib/locale'); const { BaseScreenComponent } = require('../base-screen.js'); diff --git a/packages/app-mobile/components/screens/search.js b/packages/app-mobile/components/screens/search.js index 75dd9bbc9..50b8a4806 100644 --- a/packages/app-mobile/components/screens/search.js +++ b/packages/app-mobile/components/screens/search.js @@ -2,7 +2,7 @@ const React = require('react'); const { StyleSheet, View, TextInput, FlatList, TouchableHighlight } = require('react-native'); const { connect } = require('react-redux'); -const { ScreenHeader } = require('../screen-header.js'); +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; diff --git a/packages/app-mobile/components/screens/status.js b/packages/app-mobile/components/screens/status.js index 04d03a423..8f8ddcd8c 100644 --- a/packages/app-mobile/components/screens/status.js +++ b/packages/app-mobile/components/screens/status.js @@ -3,7 +3,7 @@ const React = require('react'); const { View, Text, Button, FlatList } = require('react-native'); const Setting = require('@joplin/lib/models/Setting').default; const { connect } = require('react-redux'); -const { ScreenHeader } = require('../screen-header.js'); +const { ScreenHeader } = require('../ScreenHeader'); const ReportService = require('@joplin/lib/services/ReportService').default; const { _ } = require('@joplin/lib/locale'); const { BaseScreenComponent } = require('../base-screen.js'); diff --git a/packages/app-mobile/components/screens/tags.js b/packages/app-mobile/components/screens/tags.js index 6e966310b..df81d7ec3 100644 --- a/packages/app-mobile/components/screens/tags.js +++ b/packages/app-mobile/components/screens/tags.js @@ -4,7 +4,7 @@ const { View, Text, FlatList, StyleSheet, TouchableOpacity } = require('react-na const { connect } = require('react-redux'); const Tag = require('@joplin/lib/models/Tag').default; const { themeStyle } = require('../global-style.js'); -const { ScreenHeader } = require('../screen-header.js'); +const { ScreenHeader } = require('../ScreenHeader'); const { _ } = require('@joplin/lib/locale'); const { BaseScreenComponent } = require('../base-screen.js'); diff --git a/packages/app-mobile/package.json b/packages/app-mobile/package.json index ec92e68e5..94db03ef1 100644 --- a/packages/app-mobile/package.json +++ b/packages/app-mobile/package.json @@ -91,6 +91,7 @@ "@lezer/highlight": "^1.0.0", "@types/jest": "^28.1.3", "@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", diff --git a/packages/lib/models/Folder.ts b/packages/lib/models/Folder.ts index ea3c1d59d..11d781722 100644 --- a/packages/lib/models/Folder.ts +++ b/packages/lib/models/Folder.ts @@ -14,7 +14,7 @@ const { substrWithEllipsis } = require('../string-utils.js'); const logger = Logger.create('models/Folder'); -interface FolderEntityWithChildren extends FolderEntity { +export interface FolderEntityWithChildren extends FolderEntity { children?: FolderEntity[]; } @@ -609,7 +609,7 @@ export default class Folder extends BaseItem { return output.join(' / '); } - static buildTree(folders: FolderEntity[]) { + static buildTree(folders: FolderEntity[]): FolderEntityWithChildren[] { const idToFolders: Record = {}; for (let i = 0; i < folders.length; i++) { idToFolders[folders[i].id] = Object.assign({}, folders[i]); diff --git a/packages/lib/reducer.ts b/packages/lib/reducer.ts index 939022281..7d3214ba9 100644 --- a/packages/lib/reducer.ts +++ b/packages/lib/reducer.ts @@ -52,6 +52,7 @@ interface StateResourceFetcher { export interface State { notes: any[]; + noteSelectionEnabled?: boolean; notesSource: string; notesParentType: string; folders: any[]; diff --git a/yarn.lock b/yarn.lock index 6aa0f49a2..4f02db6ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4081,6 +4081,7 @@ __metadata: "@react-native-community/slider": ^3.0.3 "@types/jest": ^28.1.3 "@types/react-native": ^0.64.4 + "@types/react-redux": ^7.1.24 assert-browserify: ^2.0.0 babel-plugin-module-resolver: ^4.1.0 buffer: ^5.0.8 @@ -6956,6 +6957,18 @@ __metadata: languageName: node linkType: hard +"@types/react-redux@npm:^7.1.24": + version: 7.1.24 + resolution: "@types/react-redux@npm:7.1.24" + dependencies: + "@types/hoist-non-react-statics": ^3.3.0 + "@types/react": "*" + hoist-non-react-statics: ^3.3.0 + redux: ^4.0.0 + checksum: 6582246581331ac7fbbd44aa1f1c136c8a9c8febbcf462432ac81302263308c21e1a2e7868beb7f73bbcb52a8e67935d133cb37f5bdcb6564eaff3a811805101 + languageName: node + linkType: hard + "@types/react-test-renderer@npm:*": version: 17.0.1 resolution: "@types/react-test-renderer@npm:17.0.1"