import { PluginItem } from '@joplin/lib/components/shared/config/plugins/types'; import * as React from 'react'; import { _ } from '@joplin/lib/locale'; import { useCallback, useMemo } from 'react'; import { Card, Divider, List, Portal, Switch, Text } from 'react-native-paper'; import getPluginIssueReportUrl from '@joplin/lib/services/plugins/utils/getPluginIssueReportUrl'; import { Linking, ScrollView, StyleSheet, View, ViewStyle } from 'react-native'; import DismissibleDialog, { DialogSize } from '../../../DismissibleDialog'; import openWebsiteForPlugin from './utils/openWebsiteForPlugin'; import PluginService, { PluginSettings } from '@joplin/lib/services/plugins/PluginService'; import PluginTitle from './PluginBox/PluginTitle'; import ActionButton from './buttons/ActionButton'; import TextButton, { ButtonType } from '../../../buttons/TextButton'; import useUpdateState, { UpdateState } from './utils/useUpdateState'; import { PluginCallback, PluginCallbacks } from './utils/usePluginCallbacks'; import usePluginItem from './utils/usePluginItem'; import InstallButton from './buttons/InstallButton'; import { InstallState } from './PluginBox'; import PluginChips from './PluginBox/PluginChips'; import { PluginStatusRecord } from '../types'; interface Props { themeId: number; visible: boolean; item: PluginItem|null; updatablePluginIds: PluginStatusRecord; updatingPluginIds: PluginStatusRecord; installingPluginIds: PluginStatusRecord; pluginCallbacks: PluginCallbacks; pluginSettings: PluginSettings; onModalDismiss: ()=> void; } const styles = (() => { const baseButtonContainer: ViewStyle = { display: 'flex', flexDirection: 'column', gap: 20, marginLeft: 10, marginRight: 10, }; return StyleSheet.create({ descriptionText: { marginTop: 5, marginBottom: 5, }, buttonContainer: { ...baseButtonContainer, marginTop: 26, marginBottom: 26, }, accordionContent: { ...baseButtonContainer, marginTop: 12, }, fraudulentPluginButton: { opacity: 0.6, }, enabledSwitchContainer: { display: 'flex', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 10, marginTop: 12, marginBottom: 14, }, pluginDescriptionContainer: { marginTop: 8, gap: 8, }, }); })(); interface EnabledSwitchProps { item: PluginItem; onToggle: PluginCallback; } const EnabledSwitch: React.FC = props => { const onChange = useCallback((value: boolean) => { if (value !== props.item.enabled) { props.onToggle({ item: props.item }); } }, [props.item, props.onToggle]); if (!props.item?.installed || props.item.deleted) { return null; } return {_('Enabled')} ; }; const PluginInfoModalContent: React.FC = props => { const initialItem = props.item; const pluginId = initialItem.manifest.id; const item = usePluginItem(pluginId, props.pluginSettings, initialItem); const manifest = item.manifest; const isCompatible = useMemo(() => { return PluginService.instance().isCompatible(manifest); }, [manifest]); const plugin = useMemo(() => { const service = PluginService.instance(); if (!service.pluginIds.includes(pluginId)) { return null; } return service.pluginById(pluginId); }, [pluginId]); const updateState = useUpdateState({ pluginId: plugin?.id, pluginSettings: props.pluginSettings, updatablePluginIds: props.updatablePluginIds, updatingPluginIds: props.updatingPluginIds, }); const aboutPlugin = ( {_('by %s', manifest.author)} {manifest.description} ); const onAboutPress = useCallback(() => { void openWebsiteForPlugin({ item }); }, [item]); const reportIssueUrl = useMemo(() => { return getPluginIssueReportUrl(manifest); }, [manifest]); const onReportIssuePress = useCallback(() => { void Linking.openURL(reportIssueUrl); }, [reportIssueUrl]); const reportIssueButton = ( {_('Report an issue')} ); const onReportFraudulentPress = useCallback(() => { void Linking.openURL('https://github.com/laurent22/joplin/security/advisories/new'); }, []); const getUpdateButtonTitle = () => { if (updateState === UpdateState.Updating) return _('Updating...'); if (updateState === UpdateState.HasBeenUpdated) return _('Updated'); return _('Update'); }; const updateButton = ( ); const installState = (() => { if (item.installed) return InstallState.Installed; if (props.installingPluginIds[pluginId]) return InstallState.Installing; return InstallState.NotInstalled; })(); const installButton = ( ); const deleteButton = ( ); const deleteButtonContainer = <> {deleteButton} ; const reportIssuesContainer = ( {_('Report fraudulent plugin')} {reportIssueButton} ); return <> {aboutPlugin} {!item.installed ? installButton : null} {_('About')} {updateState !== UpdateState.Idle ? updateButton : null} { item.installed ? deleteButtonContainer : null } {reportIssuesContainer} ; }; const PluginInfoModal: React.FC = props => { return ( { props.item ? : null } ); }; export default PluginInfoModal;