mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-18 09:35:20 +02:00
117 lines
3.4 KiB
TypeScript
117 lines
3.4 KiB
TypeScript
import * as React from 'react';
|
|
|
|
import { AppType, SettingMetadataSection, SettingSectionSource } from '@joplin/lib/models/Setting';
|
|
import { FunctionComponent, useEffect, useMemo, useState } from 'react';
|
|
import { ConfigScreenStyles } from '../configScreenStyles';
|
|
import { FlatList, View, ViewStyle } from 'react-native';
|
|
import { Text } from 'react-native-paper';
|
|
import { settingsSections } from '@joplin/lib/components/shared/config/config-shared';
|
|
import { _ } from '@joplin/lib/locale';
|
|
import SectionTab from './SectionTab';
|
|
|
|
interface Props {
|
|
styles: ConfigScreenStyles;
|
|
|
|
width: number|undefined;
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
|
settings: Record<string, any>;
|
|
selectedSectionName: string|null;
|
|
openSection: (sectionName: string)=> void;
|
|
}
|
|
type SectionDivider = { divider: boolean; label: string; name: string; source?: string };
|
|
|
|
const SectionSelector: FunctionComponent<Props> = props => {
|
|
type SectionListType = (SectionDivider|SettingMetadataSection)[];
|
|
const sections = useMemo((): SectionListType => {
|
|
const allSections = settingsSections({ device: AppType.Mobile, settings: props.settings });
|
|
|
|
const builtInSections = [];
|
|
const pluginSections = [];
|
|
for (const section of allSections) {
|
|
if (section.source === SettingSectionSource.Plugin) {
|
|
pluginSections.push(section);
|
|
} else {
|
|
builtInSections.push(section);
|
|
}
|
|
}
|
|
|
|
let result: SectionListType = builtInSections;
|
|
if (pluginSections.length > 0) {
|
|
result = result.concat([
|
|
{ label: _('Plugins'), name: 'plugins-divider', divider: true },
|
|
...pluginSections,
|
|
]);
|
|
}
|
|
return result;
|
|
}, [props.settings]);
|
|
|
|
const styles = props.styles.styleSheet;
|
|
const onRenderButton = ({ item }: { item: SettingMetadataSection|SectionDivider }) => {
|
|
const section = item;
|
|
const selected = props.selectedSectionName === section.name;
|
|
|
|
if ('divider' in item && item.divider) {
|
|
return (
|
|
<View style={styles.sidebarHeader}>
|
|
<Text variant='labelLarge' style={styles.sidebarHeaderText}>{item.label}</Text>
|
|
</View>
|
|
);
|
|
} else {
|
|
return (
|
|
<SectionTab
|
|
selected={selected}
|
|
section={section as SettingMetadataSection}
|
|
styles={props.styles}
|
|
onPress={() => props.openSection(section.name)}
|
|
/>
|
|
);
|
|
}
|
|
};
|
|
|
|
const [flatListRef, setFlatListRef] = useState<FlatList|null>(null);
|
|
|
|
useEffect(() => {
|
|
if (flatListRef && props.selectedSectionName) {
|
|
let selectedIndex = 0;
|
|
for (const section of sections) {
|
|
if (section.name === props.selectedSectionName) {
|
|
break;
|
|
}
|
|
selectedIndex ++;
|
|
}
|
|
|
|
flatListRef.scrollToIndex({
|
|
index: selectedIndex,
|
|
viewPosition: 0.5,
|
|
});
|
|
}
|
|
}, [props.selectedSectionName, flatListRef, sections]);
|
|
|
|
const containerStyle: ViewStyle = useMemo(() => ({
|
|
width: props.width,
|
|
maxWidth: props.width,
|
|
minWidth: props.width,
|
|
flex: 1,
|
|
}), [props.width]);
|
|
|
|
return (
|
|
<View style={containerStyle}>
|
|
<FlatList
|
|
role='tablist'
|
|
ref={setFlatListRef}
|
|
data={sections}
|
|
renderItem={onRenderButton}
|
|
keyExtractor={item => item.name}
|
|
onScrollToIndexFailed={({ index, averageItemLength }) => {
|
|
// Scrolling to a particular index can fail if the item at that index hasn't been rendered yet.
|
|
// This shouldn't happen often, so a guess should be sufficient.
|
|
flatListRef.scrollToOffset({ offset: (index + 0.5) * averageItemLength });
|
|
}}
|
|
/>
|
|
</View>
|
|
);
|
|
};
|
|
|
|
export default SectionSelector;
|