1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-18 09:35:20 +02:00
joplin/packages/app-mobile/components/screens/ConfigScreen/SectionSelector/index.tsx

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;