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;