import * as React from 'react'; import { useCallback, useMemo } from 'react'; import createRootStyle from '../../utils/createRootStyle'; import { View, StyleSheet, ScrollView } from 'react-native'; import { Divider, Text, TouchableRipple } from 'react-native-paper'; import { _ } from '@joplin/lib/locale'; import { themeStyle } from '../global-style'; import { connect } from 'react-redux'; import ToolbarButtonUtils, { ToolbarButtonInfo, ToolbarItem } from '@joplin/lib/services/commands/ToolbarButtonUtils'; import Icon from '../Icon'; import { AppState } from '../../utils/types'; import CommandService from '@joplin/lib/services/CommandService'; import allToolbarCommandNamesFromState from './utils/allToolbarCommandNamesFromState'; import Setting from '@joplin/lib/models/Setting'; import DismissibleDialog, { DialogSize } from '../DismissibleDialog'; import selectedCommandNamesFromState from './utils/selectedCommandNamesFromState'; import stateToWhenClauseContext from '../../services/commands/stateToWhenClauseContext'; import { DeleteButton } from '../buttons'; import shim from '@joplin/lib/shim'; const toolbarButtonUtils = new ToolbarButtonUtils(CommandService.instance()); interface EditorDialogProps { themeId: number; defaultToolbarButtonInfos: ToolbarItem[]; selectedCommandNames: string[]; allCommandNames: string[]; hasCustomizedLayout: boolean; visible: boolean; onDismiss: ()=> void; } const useStyle = (themeId: number) => { return useMemo(() => { const theme = themeStyle(themeId); return StyleSheet.create({ ...createRootStyle(themeId), icon: { color: theme.color, fontSize: theme.fontSizeLarge, }, labelText: { fontSize: theme.fontSize, }, listContainer: { marginTop: theme.marginTop, flex: 1, }, resetButton: { marginTop: theme.marginTop, }, listItem: { flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start', gap: theme.margin, padding: 4, paddingTop: theme.itemMarginTop, paddingBottom: theme.itemMarginBottom, }, }); }, [themeId]); }; type Styles = ReturnType; const setCommandIncluded = ( commandName: string, lastSelectedCommands: string[], allCommandNames: string[], include: boolean, ) => { let newSelectedCommands; if (include) { newSelectedCommands = []; for (const name of allCommandNames) { const isDivider = name === '-'; if (isDivider || name === commandName || lastSelectedCommands.includes(name)) { newSelectedCommands.push(name); } } } else { newSelectedCommands = lastSelectedCommands.filter(name => name !== commandName); } Setting.setValue('editor.toolbarButtons', newSelectedCommands); }; interface ItemToggleProps { item: ToolbarButtonInfo; selectedCommandNames: string[]; allCommandNames: string[]; styles: Styles; } const ToolbarItemToggle: React.FC = ({ item, selectedCommandNames, styles, allCommandNames, }) => { const title = item.title || item.tooltip; const checked = selectedCommandNames.includes(item.name); const onToggle = useCallback(() => { setCommandIncluded(item.name, selectedCommandNames, allCommandNames, !checked); }, [item, selectedCommandNames, allCommandNames, checked]); return ( {title} ); }; const ToolbarEditorScreen: React.FC = props => { const styles = useStyle(props.themeId); const renderItem = (item: ToolbarItem, index: number) => { if (item.type === 'separator') { return ; } return ; }; const onRestoreDefaultLayout = useCallback(async () => { // Dismiss before showing the confirm dialog to prevent modal conflicts. // On some platforms (web and possibly iOS) showing multiple modals // at the same time can cause issues. props.onDismiss(); const message = _('Are you sure that you want to restore the default toolbar layout?\nThis cannot be undone.'); if (await shim.showConfirmationDialog(message)) { Setting.setValue('editor.toolbarButtons', []); } }, [props.onDismiss]); const restoreButton = {_('Restore defaults')} ; return ( {_('Check elements to display in the toolbar')} {props.defaultToolbarButtonInfos.map((item, index) => renderItem(item, index))} {props.hasCustomizedLayout ? restoreButton : null} ); }; export default connect((state: AppState) => { const whenClauseContext = stateToWhenClauseContext(state); const allCommandNames = allToolbarCommandNamesFromState(state); const selectedCommandNames = selectedCommandNamesFromState(state); return { themeId: state.settings.theme, selectedCommandNames, allCommandNames, hasCustomizedLayout: state.settings['editor.toolbarButtons'].length > 0, defaultToolbarButtonInfos: toolbarButtonUtils.commandsToToolbarButtons(allCommandNames, whenClauseContext), }; })(ToolbarEditorScreen);