import * as React from 'react'; import { Icon, Card, Chip, Text } from 'react-native-paper'; import { _ } from '@joplin/lib/locale'; import { Alert, Linking, StyleSheet, View } from 'react-native'; 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'; import PluginInfoButton from './PluginInfoButton'; export enum InstallState { NotInstalled, Installing, Installed, } export enum UpdateState { Idle = 1, CanUpdate = 2, Updating = 3, HasBeenUpdated = 4, } interface Props { themeId: number; item: PluginItem; isCompatible: boolean; hasErrors?: boolean; installState?: InstallState; updateState?: UpdateState; onAboutPress?: PluginCallback; onInstall?: PluginCallback; onUpdate?: PluginCallback; onDelete?: PluginCallback; onToggle?: PluginCallback; onShowPluginLog?: PluginCallback; } const onRecommendedPress = () => { Alert.alert( '', _('The Joplin team has vetted this plugin and it meets our standards for security and performance.'), [ { text: _('Learn more'), onPress: () => Linking.openURL('https://github.com/joplin/plugins/blob/master/readme/recommended.md'), }, { text: _('OK'), }, ], { cancelable: true }, ); }; // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied const PluginIcon = (props: any) => ; const styles = StyleSheet.create({ versionText: { opacity: 0.8, }, title: { // Prevents the title text from being clipped on Android verticalAlign: 'middle', }, }); const PluginBox: React.FC = props => { const manifest = props.item.manifest; const item = props.item; const installButtonTitle = () => { if (props.installState === InstallState.Installing) return _('Installing...'); if (props.installState === InstallState.NotInstalled) return _('Install'); if (props.installState === InstallState.Installed) return _('Installed'); return `Invalid install state: ${props.installState}`; }; const installButton = ( ); const getUpdateButtonTitle = () => { if (props.updateState === UpdateState.Updating) return _('Updating...'); if (props.updateState === UpdateState.HasBeenUpdated) return _('Updated'); return _('Update'); }; const updateButton = ( ); const deleteButton = ( ); const disableButton = ; const enableButton = ; const aboutButton = ; const renderErrorsChip = () => { if (!props.hasErrors) return null; return ( props.onShowPluginLog({ item })} > {_('Error')} ); }; const renderRecommendedChip = () => { if (!props.item.manifest._recommended || !props.isCompatible) { return null; } return {_('Recommended')} ; }; const renderBuiltInChip = () => { if (!props.item.builtIn) { return null; } return {_('Built-in')}; }; const renderIncompatibleChip = () => { if (props.isCompatible) return null; return ( { void shim.showMessageBox( PluginService.instance().describeIncompatibility(props.item.manifest), { buttons: [_('OK')] }, ); }} >{_('Incompatible')} ); }; const renderRightEdgeButton = (buttonProps: { size: number }) => { // If .onAboutPress is given (e.g. when searching), there's another way to get information // about the plugin. In this case, we don't show the right-side information link. if (props.onAboutPress) return null; return ; }; const updateStateIsIdle = props.updateState !== UpdateState.Idle; const titleComponent = <> {manifest.name} v{manifest.version} ; return ( {renderIncompatibleChip()} {renderErrorsChip()} {renderRecommendedChip()} {renderBuiltInChip()} {props.onAboutPress ? aboutButton : null} {props.onInstall ? installButton : null} {props.onDelete && !props.item.builtIn ? deleteButton : null} {props.onUpdate && updateStateIsIdle ? updateButton : null} {props.onToggle && props.item.enabled ? disableButton : null} {props.onToggle && !props.item.enabled ? enableButton : null} ); }; export default PluginBox;