mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-02 12:47:41 +02:00
Chore: Mobile: Plugin settings screen: Improve accessibility and tests (#10267)
This commit is contained in:
parent
03c3feef16
commit
a2071bfed2
@ -577,7 +577,8 @@ packages/app-mobile/components/screens/ConfigScreen/SettingItem.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingsButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingsToggle.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/ActionButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/index.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.test.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginToggle.js
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -557,7 +557,8 @@ packages/app-mobile/components/screens/ConfigScreen/SettingItem.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingsButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/SettingsToggle.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/configScreenStyles.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/ActionButton.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginBox/index.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.test.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginStates.js
|
||||
packages/app-mobile/components/screens/ConfigScreen/plugins/PluginToggle.js
|
||||
|
@ -0,0 +1,35 @@
|
||||
import * as React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
import { ItemEvent, PluginItem } from '@joplin/lib/components/shared/config/plugins/types';
|
||||
import { Button, ButtonProps } from 'react-native-paper';
|
||||
|
||||
export type PluginCallback = (event: ItemEvent)=> void;
|
||||
|
||||
interface Props extends Omit<ButtonProps, 'item'|'onPress'|'children'> {
|
||||
item: PluginItem;
|
||||
onPress?: PluginCallback;
|
||||
title: string;
|
||||
}
|
||||
|
||||
const ActionButton: React.FC<Props> = props => {
|
||||
const onPress = useCallback(() => {
|
||||
props.onPress?.({ item: props.item });
|
||||
}, [props.onPress, props.item]);
|
||||
|
||||
// Include additional information about the button when using a screen
|
||||
// reader (helps make it clear which plugin a delete/enable button).
|
||||
//
|
||||
// Because this is being read by a screen reader and to reduce load on
|
||||
// translators, the method of joining the title and manifest name is not
|
||||
// marked as translatable.
|
||||
const accessibilityLabel = `${props.title} ${props.item.manifest.name}`;
|
||||
return (
|
||||
<Button
|
||||
{...props}
|
||||
onPress={onPress}
|
||||
accessibilityLabel={accessibilityLabel}
|
||||
>{props.title}</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default ActionButton;
|
@ -1,10 +1,11 @@
|
||||
import * as React from 'react';
|
||||
import { Icon, Button, Card, Chip } from 'react-native-paper';
|
||||
import { Icon, Card, Chip } from 'react-native-paper';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { View } from 'react-native';
|
||||
import { ItemEvent, PluginItem } from '@joplin/lib/components/shared/config/plugins/types';
|
||||
import { PluginItem } from '@joplin/lib/components/shared/config/plugins/types';
|
||||
import shim from '@joplin/lib/shim';
|
||||
import PluginService from '@joplin/lib/services/plugins/PluginService';
|
||||
import ActionButton, { PluginCallback } from './ActionButton';
|
||||
|
||||
export enum InstallState {
|
||||
NotInstalled,
|
||||
@ -19,8 +20,6 @@ export enum UpdateState {
|
||||
HasBeenUpdated = 4,
|
||||
}
|
||||
|
||||
type PluginCallback = (event: ItemEvent)=> void;
|
||||
|
||||
interface Props {
|
||||
item: PluginItem;
|
||||
isCompatible: boolean;
|
||||
@ -52,41 +51,42 @@ const PluginBox: React.FC<Props> = props => {
|
||||
};
|
||||
|
||||
const installButton = (
|
||||
<Button
|
||||
onPress={() => props.onInstall?.({ item })}
|
||||
<ActionButton
|
||||
item={item}
|
||||
onPress={props.onInstall}
|
||||
disabled={props.installState !== InstallState.NotInstalled || !props.isCompatible}
|
||||
loading={props.installState === InstallState.Installing}
|
||||
>
|
||||
{installButtonTitle()}
|
||||
</Button>
|
||||
title={installButtonTitle()}
|
||||
/>
|
||||
);
|
||||
|
||||
const updateButtonTitle = () => {
|
||||
const getUpdateButtonTitle = () => {
|
||||
if (props.updateState === UpdateState.Updating) return _('Updating...');
|
||||
if (props.updateState === UpdateState.HasBeenUpdated) return _('Updated');
|
||||
return _('Update');
|
||||
};
|
||||
|
||||
const updateButton = (
|
||||
<Button
|
||||
onPress={() => props.onUpdate?.({ item })}
|
||||
<ActionButton
|
||||
item={item}
|
||||
onPress={props.onUpdate}
|
||||
disabled={props.updateState !== UpdateState.CanUpdate || !props.isCompatible}
|
||||
loading={props.updateState === UpdateState.Updating}
|
||||
>
|
||||
{updateButtonTitle()}
|
||||
</Button>
|
||||
title={getUpdateButtonTitle()}
|
||||
/>
|
||||
);
|
||||
|
||||
const deleteButton = (
|
||||
<Button
|
||||
onPress={() => props.onDelete?.({ item })}
|
||||
<ActionButton
|
||||
item={item}
|
||||
onPress={props.onDelete}
|
||||
disabled={props.item.deleted}
|
||||
>
|
||||
{props.item.deleted ? _('Deleted') : _('Delete')}
|
||||
</Button>
|
||||
title={props.item.deleted ? _('Deleted') : _('Delete')}
|
||||
/>
|
||||
);
|
||||
const disableButton = <Button onPress={() => props.onToggle?.({ item })}>{_('Disable')}</Button>;
|
||||
const enableButton = <Button onPress={() => props.onToggle?.({ item })}>{_('Enable')}</Button>;
|
||||
const aboutButton = <Button icon='web' onPress={() => props.onAboutPress?.({ item })}>{_('About')}</Button>;
|
||||
const disableButton = <ActionButton item={item} onPress={props.onToggle} title={_('Disable')}/>;
|
||||
const enableButton = <ActionButton item={item} onPress={props.onToggle} title={_('Enable')}/>;
|
||||
const aboutButton = <ActionButton icon='web' item={item} onPress={props.onAboutPress} title={_('About')}/>;
|
||||
|
||||
const renderErrorsChip = () => {
|
||||
if (!props.hasErrors) return null;
|
||||
@ -97,7 +97,7 @@ const PluginBox: React.FC<Props> = props => {
|
||||
mode='outlined'
|
||||
onPress={() => props.onShowPluginLog({ item })}
|
||||
>
|
||||
Error
|
||||
{_('Error')}
|
||||
</Chip>
|
||||
);
|
||||
};
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import RepositoryApi from '@joplin/lib/services/plugins/RepositoryApi';
|
||||
import { afterAllCleanUp, afterEachCleanUp, createTempDir, mockMobilePlatform, setupDatabaseAndSynchronizer, supportDir, switchClient } from '@joplin/lib/testing/test-utils';
|
||||
|
||||
import { render, screen, waitFor } from '@testing-library/react-native';
|
||||
import { render, screen } from '@testing-library/react-native';
|
||||
import '@testing-library/react-native/extend-expect';
|
||||
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
@ -124,18 +124,17 @@ describe('PluginStates', () => {
|
||||
initialPluginSettings={defaultPluginSettings}
|
||||
/>,
|
||||
);
|
||||
expect(await screen.findByText('ABC Sheet Music')).not.toBeNull();
|
||||
expect(await screen.findByText('Backlinks to note')).not.toBeNull();
|
||||
expect(await screen.findByText('ABC Sheet Music')).toBeVisible();
|
||||
expect(await screen.findByText('Backlinks to note')).toBeVisible();
|
||||
|
||||
const shouldBothBeUpdatable = platform === 'android';
|
||||
await waitFor(async () => {
|
||||
const updateButtons = await screen.findAllByText('Update');
|
||||
expect(updateButtons).toHaveLength(shouldBothBeUpdatable ? 2 : 1);
|
||||
});
|
||||
expect(await screen.findByRole('button', { name: 'Update ABC Sheet Music', disabled: false })).toBeVisible();
|
||||
|
||||
const updateButtons = await screen.findAllByText('Update');
|
||||
for (const button of updateButtons) {
|
||||
expect(button).not.toBeDisabled();
|
||||
// Backlinks to note should not be updatable on iOS (it's not _recommended).
|
||||
const backlinksToNoteQuery = { name: 'Update Backlinks to note', disabled: false };
|
||||
if (platform === 'android') {
|
||||
expect(await screen.findByRole('button', backlinksToNoteQuery)).toBeVisible();
|
||||
} else {
|
||||
expect(await screen.queryByRole('button', backlinksToNoteQuery)).toBeNull();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user