2023-11-09 21:19:08 +02:00
|
|
|
import * as React from 'react';
|
|
|
|
|
2024-03-11 17:02:15 +02:00
|
|
|
import Setting, { AppType, SettingMetadataSection, SettingSectionSource } from '@joplin/lib/models/Setting';
|
2023-11-09 21:19:08 +02:00
|
|
|
import { FunctionComponent, useEffect, useMemo, useState } from 'react';
|
|
|
|
import { ConfigScreenStyles } from './configScreenStyles';
|
2024-06-11 08:41:50 +02:00
|
|
|
import { FlatList, Text, View, ViewStyle } from 'react-native';
|
2023-11-09 21:19:08 +02:00
|
|
|
import { settingsSections } from '@joplin/lib/components/shared/config/config-shared';
|
|
|
|
import Icon from '../../Icon';
|
2024-03-11 17:02:15 +02:00
|
|
|
import { _ } from '@joplin/lib/locale';
|
2024-06-11 08:41:50 +02:00
|
|
|
import { TouchableRipple } from 'react-native-paper';
|
2024-06-14 20:38:50 +02:00
|
|
|
import BetaChip from '../../BetaChip';
|
2023-11-09 21:19:08 +02:00
|
|
|
|
|
|
|
interface Props {
|
|
|
|
styles: ConfigScreenStyles;
|
|
|
|
|
|
|
|
width: number|undefined;
|
|
|
|
|
2024-04-05 13:16:49 +02:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
2023-11-09 21:19:08 +02:00
|
|
|
settings: any;
|
|
|
|
selectedSectionName: string|null;
|
|
|
|
openSection: (sectionName: string)=> void;
|
|
|
|
}
|
|
|
|
|
|
|
|
const SectionSelector: FunctionComponent<Props> = props => {
|
|
|
|
const sections = useMemo(() => {
|
|
|
|
return settingsSections({ device: AppType.Mobile, settings: props.settings });
|
|
|
|
}, [props.settings]);
|
|
|
|
const styles = props.styles.styleSheet;
|
|
|
|
|
|
|
|
const itemHeight = styles.sidebarButton.height;
|
|
|
|
|
|
|
|
const onRenderButton = ({ item }: { item: SettingMetadataSection }) => {
|
|
|
|
const section = item;
|
|
|
|
const selected = props.selectedSectionName === section.name;
|
|
|
|
const icon = Setting.sectionNameToIcon(section.name, AppType.Mobile);
|
|
|
|
const label = Setting.sectionNameToLabel(section.name);
|
|
|
|
const shortDescription = Setting.sectionMetadataToSummary(section);
|
2024-03-11 17:02:15 +02:00
|
|
|
const isPlugin = item.source === SettingSectionSource.Plugin;
|
|
|
|
|
|
|
|
const titleStyle = selected ? styles.sidebarSelectedButtonText : styles.sidebarButtonMainText;
|
|
|
|
|
|
|
|
const sourceIcon = isPlugin ? (
|
|
|
|
<Icon
|
|
|
|
name='fas fa-puzzle-piece'
|
|
|
|
accessibilityLabel={_('From a plugin')}
|
|
|
|
style={titleStyle}
|
|
|
|
/>
|
|
|
|
) : null;
|
2023-11-09 21:19:08 +02:00
|
|
|
|
2024-06-14 20:38:50 +02:00
|
|
|
const isBeta = item.name === 'plugins';
|
|
|
|
const betaChip = isBeta ? <BetaChip size={10}/> : null;
|
|
|
|
|
2023-11-09 21:19:08 +02:00
|
|
|
return (
|
2024-06-11 08:41:50 +02:00
|
|
|
<TouchableRipple
|
2023-11-09 21:19:08 +02:00
|
|
|
key={section.name}
|
|
|
|
role='tab'
|
|
|
|
aria-selected={selected}
|
|
|
|
onPress={() => props.openSection(section.name)}
|
|
|
|
>
|
2024-06-11 08:41:50 +02:00
|
|
|
<View
|
|
|
|
style={selected ? styles.selectedSidebarButton : styles.sidebarButton}
|
|
|
|
>
|
|
|
|
<Icon
|
|
|
|
name={icon}
|
|
|
|
accessibilityLabel={null}
|
|
|
|
style={styles.sidebarIcon}
|
|
|
|
/>
|
|
|
|
<View style={{ display: 'flex', flexDirection: 'column', flex: 1 }}>
|
2024-06-14 20:38:50 +02:00
|
|
|
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
|
|
|
|
<Text
|
|
|
|
numberOfLines={1}
|
|
|
|
style={titleStyle}
|
|
|
|
>
|
|
|
|
{label}
|
|
|
|
</Text>
|
|
|
|
|
|
|
|
{betaChip}
|
|
|
|
</View>
|
2024-06-11 08:41:50 +02:00
|
|
|
<Text
|
|
|
|
style={styles.sidebarButtonDescriptionText}
|
|
|
|
numberOfLines={1}
|
|
|
|
ellipsizeMode='tail'
|
|
|
|
>
|
|
|
|
{shortDescription ?? ''}
|
|
|
|
</Text>
|
|
|
|
</View>
|
|
|
|
{sourceIcon}
|
2023-11-09 21:19:08 +02:00
|
|
|
</View>
|
2024-06-11 08:41:50 +02:00
|
|
|
</TouchableRipple>
|
2023-11-09 21:19:08 +02:00
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
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]);
|
|
|
|
|
2023-11-11 19:09:34 +02:00
|
|
|
const containerStyle: ViewStyle = useMemo(() => ({
|
|
|
|
width: props.width,
|
|
|
|
maxWidth: props.width,
|
|
|
|
minWidth: props.width,
|
|
|
|
flex: 1,
|
|
|
|
}), [props.width]);
|
|
|
|
|
2023-11-09 21:19:08 +02:00
|
|
|
return (
|
2023-11-11 19:09:34 +02:00
|
|
|
<View style={containerStyle}>
|
2023-11-09 21:19:08 +02:00
|
|
|
<FlatList
|
|
|
|
role='tablist'
|
|
|
|
ref={setFlatListRef}
|
|
|
|
data={sections}
|
|
|
|
renderItem={onRenderButton}
|
|
|
|
keyExtractor={item => item.name}
|
|
|
|
getItemLayout={(_data, index) => ({
|
|
|
|
length: itemHeight, offset: itemHeight * index, index,
|
|
|
|
})}
|
|
|
|
/>
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
export default SectionSelector;
|