You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-02 22:49:09 +02:00
Mobile: Implement plugin screen redesign (#10465)
This commit is contained in:
@@ -4,21 +4,32 @@ import useAsyncEffect from '@joplin/lib/hooks/useAsyncEffect';
|
||||
import { _ } from '@joplin/lib/locale';
|
||||
import { PluginManifest } from '@joplin/lib/services/plugins/utils/types';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { FlatList, View } from 'react-native';
|
||||
import { Searchbar } from 'react-native-paper';
|
||||
import { FlatList, StyleSheet, View } from 'react-native';
|
||||
import { TextInput, Text } from 'react-native-paper';
|
||||
import PluginBox, { InstallState } from './PluginBox';
|
||||
import PluginService, { PluginSettings, SerializedPluginSettings } from '@joplin/lib/services/plugins/PluginService';
|
||||
import useInstallHandler from '@joplin/lib/components/shared/config/plugins/useOnInstallHandler';
|
||||
import { OnPluginSettingChangeEvent, PluginItem } from '@joplin/lib/components/shared/config/plugins/types';
|
||||
import PluginService, { PluginSettings } from '@joplin/lib/services/plugins/PluginService';
|
||||
import { PluginItem } from '@joplin/lib/components/shared/config/plugins/types';
|
||||
import RepositoryApi from '@joplin/lib/services/plugins/RepositoryApi';
|
||||
import openWebsiteForPlugin from './utils/openWebsiteForPlugin';
|
||||
import { PluginCallback, PluginCallbacks } from './utils/usePluginCallbacks';
|
||||
import InstalledPluginBox from './InstalledPluginBox';
|
||||
|
||||
interface Props {
|
||||
themeId: number;
|
||||
pluginSettings: SerializedPluginSettings;
|
||||
pluginSettings: PluginSettings;
|
||||
repoApiInitialized: boolean;
|
||||
onUpdatePluginStates: (states: PluginSettings)=> void;
|
||||
repoApi: RepositoryApi;
|
||||
|
||||
installingPluginIds: Record<string, boolean>;
|
||||
updatingPluginIds: Record<string, boolean>;
|
||||
updatablePluginIds: Record<string, boolean>;
|
||||
|
||||
callbacks: PluginCallbacks;
|
||||
onShowPluginInfo: PluginCallback;
|
||||
|
||||
searchQuery: string;
|
||||
setSearchQuery: (newQuery: string)=> void;
|
||||
}
|
||||
|
||||
interface SearchResultRecord {
|
||||
@@ -27,8 +38,20 @@ interface SearchResultRecord {
|
||||
installState: InstallState;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flexDirection: 'column',
|
||||
margin: 12,
|
||||
},
|
||||
resultsCounter: {
|
||||
margin: 12,
|
||||
marginTop: 17,
|
||||
marginBottom: 4,
|
||||
},
|
||||
});
|
||||
|
||||
const PluginSearch: React.FC<Props> = props => {
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const { searchQuery, setSearchQuery } = props;
|
||||
const [searchResultManifests, setSearchResultManifests] = useState<PluginManifest[]>([]);
|
||||
|
||||
useAsyncEffect(async event => {
|
||||
@@ -42,8 +65,6 @@ const PluginSearch: React.FC<Props> = props => {
|
||||
}
|
||||
}, [searchQuery, props.repoApi, setSearchResultManifests, props.repoApiInitialized]);
|
||||
|
||||
const [installingPluginsIds, setInstallingPluginIds] = useState<Record<string, boolean>>({});
|
||||
|
||||
const pluginSettings = useMemo(() => {
|
||||
return { ...PluginService.instance().unserializePluginSettings(props.pluginSettings) };
|
||||
}, [props.pluginSettings]);
|
||||
@@ -56,12 +77,13 @@ const PluginSearch: React.FC<Props> = props => {
|
||||
if (settings && !settings.deleted) {
|
||||
installState = InstallState.Installed;
|
||||
}
|
||||
if (installingPluginsIds[manifest.id]) {
|
||||
if (props.installingPluginIds[manifest.id]) {
|
||||
installState = InstallState.Installing;
|
||||
}
|
||||
|
||||
const item: PluginItem = {
|
||||
manifest,
|
||||
installed: !!settings,
|
||||
enabled: settings && settings.enabled,
|
||||
deleted: settings && !settings.deleted,
|
||||
devMode: false,
|
||||
@@ -75,41 +97,62 @@ const PluginSearch: React.FC<Props> = props => {
|
||||
installState,
|
||||
};
|
||||
});
|
||||
}, [searchResultManifests, installingPluginsIds, pluginSettings]);
|
||||
}, [searchResultManifests, props.installingPluginIds, pluginSettings]);
|
||||
|
||||
const onPluginSettingsChange = useCallback((event: OnPluginSettingChangeEvent) => {
|
||||
props.onUpdatePluginStates(event.value);
|
||||
}, [props.onUpdatePluginStates]);
|
||||
|
||||
const installPlugin = useInstallHandler(
|
||||
setInstallingPluginIds, pluginSettings, props.repoApi, onPluginSettingsChange, false,
|
||||
);
|
||||
|
||||
const onInstall = props.callbacks.onInstall;
|
||||
const renderResult = useCallback(({ item }: { item: SearchResultRecord }) => {
|
||||
const manifest = item.item.manifest;
|
||||
|
||||
return (
|
||||
<PluginBox
|
||||
themeId={props.themeId}
|
||||
key={manifest.id}
|
||||
item={item.item}
|
||||
installState={item.installState}
|
||||
isCompatible={PluginService.instance().isCompatible(manifest)}
|
||||
onInstall={installPlugin}
|
||||
onAboutPress={openWebsiteForPlugin}
|
||||
/>
|
||||
);
|
||||
}, [installPlugin, props.themeId]);
|
||||
if (item.installState === InstallState.Installed && PluginService.instance().isPluginLoaded(manifest.id)) {
|
||||
return (
|
||||
<InstalledPluginBox
|
||||
pluginId={manifest.id}
|
||||
themeId={props.themeId}
|
||||
pluginSettings={props.pluginSettings}
|
||||
updatablePluginIds={props.updatablePluginIds}
|
||||
updatingPluginIds={props.updatingPluginIds}
|
||||
showInstalledChip={true}
|
||||
callbacks={props.callbacks}
|
||||
onShowPluginInfo={props.onShowPluginInfo}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<PluginBox
|
||||
themeId={props.themeId}
|
||||
key={manifest.id}
|
||||
item={item.item}
|
||||
installState={item.installState}
|
||||
showInstalledChip={false}
|
||||
isCompatible={PluginService.instance().isCompatible(manifest)}
|
||||
onInstall={onInstall}
|
||||
onAboutPress={openWebsiteForPlugin}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}, [onInstall, props.themeId, props.pluginSettings, props.updatingPluginIds, props.updatablePluginIds, props.onShowPluginInfo, props.callbacks]);
|
||||
|
||||
const renderResultsCount = () => {
|
||||
if (!searchQuery.length) return null;
|
||||
|
||||
return <Text style={styles.resultsCounter} variant='labelLarge'>
|
||||
{_('Results (%d):', searchResults.length)}
|
||||
</Text>;
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={{ flexDirection: 'column' }}>
|
||||
<Searchbar
|
||||
<View style={styles.container}>
|
||||
<TextInput
|
||||
testID='searchbar'
|
||||
placeholder={_('Search')}
|
||||
mode='outlined'
|
||||
left={<TextInput.Icon icon='magnify' />}
|
||||
placeholder={_('Search plugins')}
|
||||
onChangeText={setSearchQuery}
|
||||
value={searchQuery}
|
||||
editable={props.repoApiInitialized}
|
||||
/>
|
||||
{renderResultsCount()}
|
||||
<FlatList
|
||||
data={searchResults}
|
||||
renderItem={renderResult}
|
||||
|
||||
Reference in New Issue
Block a user