mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-21 09:38:01 +02:00
Chore: Migrate mobile Dropdown, ScreenHeader to TypeScript (#6763)
This commit is contained in:
parent
3ec3a37603
commit
92c24c2129
@ -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
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -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
|
||||
|
@ -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<DropdownProps, DropdownState> {
|
||||
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 (
|
||||
<TouchableOpacity
|
||||
style={itemWrapperStyle}
|
||||
key={item.value}
|
||||
key={key}
|
||||
onPress={() => {
|
||||
closeList();
|
||||
if (this.props.onValueChange) this.props.onValueChange(item.value);
|
||||
}}
|
||||
>
|
||||
<Text ellipsizeMode="tail" numberOfLines={1} style={itemStyle} key={item.value}>
|
||||
<Text ellipsizeMode="tail" numberOfLines={1} style={itemStyle} key={key}>
|
||||
{item.label}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
@ -111,7 +143,7 @@ class Dropdown extends React.Component {
|
||||
<View style={{ flex: 1, flexDirection: 'column' }}>
|
||||
<TouchableOpacity
|
||||
style={headerWrapperStyle}
|
||||
ref={ref => (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}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
@ -154,4 +184,5 @@ class Dropdown extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Dropdown };
|
||||
export default Dropdown;
|
||||
export { Dropdown };
|
@ -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<ScreenHeaderProps, ScreenHeaderState> {
|
||||
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 (
|
||||
<TouchableOpacity key={screen} style={this.styles().warningBox} onPress={() => this.warningBox_press({ screen: screen })} activeOpacity={0.8}>
|
||||
<Text style={{ flex: 1 }}>{message}</Text>
|
||||
@ -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 (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
@ -240,7 +293,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
function backButton(styles, onPress, disabled) {
|
||||
function backButton(styles: any, onPress: OnPressCallback, disabled: boolean) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
@ -259,7 +312,9 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
function saveButton(styles, onPress, disabled, show) {
|
||||
function saveButton(
|
||||
styles: any, onPress: OnPressCallback, disabled: boolean, show: boolean
|
||||
) {
|
||||
if (!show) return null;
|
||||
|
||||
const icon = disabled ? <Icon name="md-checkmark" style={styles.savedButtonIcon} /> : <Image style={styles.saveButtonIcon} source={require('./SaveIcon.png')} />;
|
||||
@ -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 = <Icon name={options.iconName} style={this.styles().topIcon} />;
|
||||
@ -317,7 +379,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
});
|
||||
};
|
||||
|
||||
function selectAllButton(styles, onPress) {
|
||||
function selectAllButton(styles: any, onPress: OnPressCallback) {
|
||||
return (
|
||||
<CustomButton
|
||||
onPress={onPress}
|
||||
@ -331,7 +393,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
function searchButton(styles, onPress) {
|
||||
function searchButton(styles: any, onPress: OnPressCallback) {
|
||||
return (
|
||||
<CustomButton
|
||||
onPress={onPress}
|
||||
@ -345,7 +407,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
function deleteButton(styles, onPress, disabled) {
|
||||
function deleteButton(styles: any, onPress: OnPressCallback, disabled: boolean) {
|
||||
return (
|
||||
<CustomButton
|
||||
onPress={onPress}
|
||||
@ -363,7 +425,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
function duplicateButton(styles, onPress, disabled) {
|
||||
function duplicateButton(styles: any, onPress: OnPressCallback, disabled: boolean) {
|
||||
return (
|
||||
<CustomButton
|
||||
onPress={onPress}
|
||||
@ -381,7 +443,7 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
function sortButton(styles, onPress) {
|
||||
function sortButton(styles: any, onPress: OnPressCallback) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
@ -430,12 +492,15 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
const createTitleComponent = (disabled) => {
|
||||
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 (
|
||||
<Dropdown
|
||||
items={titlePickerItems(!!folderPickerOptions.mustSelect)}
|
||||
itemHeight={35}
|
||||
disabled={disabled}
|
||||
labelTransform="trim"
|
||||
selectedValue={'selectedFolderId' in folderPickerOptions ? folderPickerOptions.selectedFolderId : null}
|
||||
@ -481,13 +545,13 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
color: theme.color,
|
||||
fontSize: theme.fontSize,
|
||||
}}
|
||||
onValueChange={async (folderId, itemIndex) => {
|
||||
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 {
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||
{sideMenuComp}
|
||||
{backButtonComp}
|
||||
{renderUndoButton(this.styles())}
|
||||
{renderRedoButton(this.styles())}
|
||||
{renderUndoButton()}
|
||||
{renderRedoButton()}
|
||||
{saveButton(
|
||||
this.styles(),
|
||||
() => {
|
||||
@ -581,20 +648,20 @@ class ScreenHeaderComponent extends React.PureComponent {
|
||||
</View>
|
||||
{warningComps}
|
||||
<DialogBox
|
||||
ref={dialogbox => {
|
||||
ref={(dialogbox: typeof DialogBox) => {
|
||||
this.dialogbox = dialogbox;
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
public static defaultProps: Partial<ScreenHeaderProps> ={
|
||||
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 };
|
@ -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);
|
||||
}}
|
||||
/>
|
||||
|
@ -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');
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
|
@ -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');
|
||||
|
@ -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');
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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<string, any> = {};
|
||||
for (let i = 0; i < folders.length; i++) {
|
||||
idToFolders[folders[i].id] = Object.assign({}, folders[i]);
|
||||
|
@ -52,6 +52,7 @@ interface StateResourceFetcher {
|
||||
|
||||
export interface State {
|
||||
notes: any[];
|
||||
noteSelectionEnabled?: boolean;
|
||||
notesSource: string;
|
||||
notesParentType: string;
|
||||
folders: any[];
|
||||
|
13
yarn.lock
13
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"
|
||||
|
Loading…
Reference in New Issue
Block a user