[IMP] Color theme & MusicList optional property
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { Select, Switch, Text, Icon, Row, Slider, useTheme } from 'native-base';
|
||||
import { Select, Switch, Text, Row, Slider, Icon, useTheme } from 'native-base';
|
||||
import { MaterialIcons } from '@expo/vector-icons';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
|
||||
import { Icon as IconSax } from 'iconsax-react-native';
|
||||
export type ElementProps = {
|
||||
title: string;
|
||||
icon?: React.ReactNode;
|
||||
icon?: IconSax;
|
||||
helperText?: string;
|
||||
description?: string;
|
||||
disabled?: boolean;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Box, Button, Column, Icon, Popover, Row, Text, useBreakpointValue } from 'native-base';
|
||||
import { Box, Button, Column, Icon, Popover, Row, Text, useBreakpointValue, useTheme } from 'native-base';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { ElementProps } from './ElementTypes';
|
||||
import {
|
||||
@@ -8,9 +8,8 @@ import {
|
||||
getElementToggleNode,
|
||||
getElementRangeNode,
|
||||
} from './ElementTypes';
|
||||
import { ArrowDown2 } from 'iconsax-react-native';
|
||||
import { ArrowDown2, Icon as IconSax } from 'iconsax-react-native';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
type RawElementProps = {
|
||||
element: ElementProps;
|
||||
@@ -21,15 +20,15 @@ export const RawElement = ({ element }: RawElementProps) => {
|
||||
const screenSize = useBreakpointValue({ base: 'small', md: 'big' });
|
||||
const isSmallScreen = screenSize === 'small';
|
||||
const { width: screenWidth } = useWindowDimensions();
|
||||
const colorScheme = useColorScheme();
|
||||
const color = colorScheme === 'light' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.7)';
|
||||
const { colors } = useTheme();
|
||||
const IconElement = icon as IconSax;
|
||||
|
||||
return (
|
||||
<Column
|
||||
style={{
|
||||
width: '100%',
|
||||
paddingVertical: 10,
|
||||
paddingHorizontal: 20,
|
||||
paddingHorizontal: isSmallScreen ? 10 : 20,
|
||||
justifyContent: 'space-between',
|
||||
alignContent: 'stretch',
|
||||
alignItems: 'center',
|
||||
@@ -44,7 +43,9 @@ export const RawElement = ({ element }: RawElementProps) => {
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{icon}
|
||||
{IconElement &&
|
||||
<IconElement size={isSmallScreen ? 18 : 24} color={colors.text[900]} style={{ minWidth: 24 }} />
|
||||
}
|
||||
<Box
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
@@ -126,7 +127,7 @@ export const RawElement = ({ element }: RawElementProps) => {
|
||||
case 'custom':
|
||||
return data;
|
||||
case 'sectionDropdown':
|
||||
return <ArrowDown2 size="24" color={color} variant="Outline" />;
|
||||
return <ArrowDown2 size="24" color={colors.text[700]} variant="Outline" />;
|
||||
default:
|
||||
return <Text>Unknown type</Text>;
|
||||
}
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
import { FlatList, HStack, View, useBreakpointValue, useTheme, Text, Row } from 'native-base';
|
||||
import MusicItem, { MusicItemType } from './MusicItem';
|
||||
import React, { useState } from 'react';
|
||||
import { ActivityIndicator } from 'react-native';
|
||||
import { ArrowDown2, ArrowRotateLeft, Chart2, Cup, Icon } from 'iconsax-react-native';
|
||||
import { StyleSheet } from 'react-native';
|
||||
import ButtonBase from './ButtonBase';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
interface MusicItemTitleProps {
|
||||
text: string;
|
||||
icon: Icon;
|
||||
isBigScreen: boolean;
|
||||
}
|
||||
|
||||
const MusicItemTitle = (props: MusicItemTitleProps) => {
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
return (
|
||||
<Row
|
||||
style={{
|
||||
display: 'flex',
|
||||
flex: 1,
|
||||
maxWidth: props.isBigScreen ? 150 : 50,
|
||||
height: '100%',
|
||||
alignItems: 'center',
|
||||
justifyContent: props.isBigScreen ? 'flex-end' : 'center',
|
||||
}}
|
||||
>
|
||||
{props.isBigScreen && (
|
||||
<Text fontSize="lg" style={{ paddingRight: 8 }}>
|
||||
{props.text}
|
||||
</Text>
|
||||
)}
|
||||
<props.icon
|
||||
size={18}
|
||||
color={colorScheme === 'light' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.7)'}
|
||||
/>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
type MusicListProps = {
|
||||
initialMusics: MusicItemType[];
|
||||
loadMoreMusics: (page: number) => Promise<MusicItemType[]>; // fonction pour charger plus de musiques
|
||||
};
|
||||
|
||||
const MusicList: React.FC<MusicListProps> = ({ initialMusics }) => {
|
||||
const [musicData, setMusicData] = useState<MusicItemType[]>(initialMusics);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { colors } = useTheme();
|
||||
const screenSize = useBreakpointValue({ base: 'small', md: 'md', xl: 'xl' });
|
||||
const isSmallScreen = screenSize === 'small';
|
||||
const isBigScreen = screenSize === 'xl';
|
||||
|
||||
const loadMoreMusicItems = () => {
|
||||
if (!loading) {
|
||||
setLoading(true);
|
||||
setTimeout(() => {
|
||||
const moreItems: MusicItemType[] = [];
|
||||
setMusicData((currentItems) => [...currentItems, ...moreItems]);
|
||||
setLoading(false);
|
||||
}, 2000); // Simule un appel réseau avec un délai de 2 secondes.
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={styles.container}>
|
||||
<HStack
|
||||
space={isSmallScreen ? 1 : 2}
|
||||
style={{
|
||||
backgroundColor: colors.coolGray[500],
|
||||
paddingHorizontal: isSmallScreen ? 8 : 16,
|
||||
paddingVertical: 12,
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
fontSize="lg"
|
||||
style={{
|
||||
flex: 4,
|
||||
width: '100%',
|
||||
justifyContent: 'center',
|
||||
paddingRight: 60,
|
||||
}}
|
||||
>
|
||||
Song
|
||||
</Text>
|
||||
{[
|
||||
{ text: 'level', icon: Chart2 },
|
||||
{ text: 'lastScore', icon: ArrowRotateLeft },
|
||||
{ text: 'BastScore', icon: Cup },
|
||||
].map((value) => (
|
||||
<MusicItemTitle
|
||||
key={value.text + 'key'}
|
||||
text={value.text}
|
||||
icon={value.icon}
|
||||
isBigScreen={isBigScreen}
|
||||
/>
|
||||
))}
|
||||
</HStack>
|
||||
<FlatList
|
||||
data={musicData}
|
||||
renderItem={({ item }) => <MusicItem style={{ marginBottom: 2 }} {...item} />}
|
||||
keyExtractor={(item) => item.artist + item.song}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.footerContainer}>
|
||||
{loading ? (
|
||||
<ActivityIndicator color={colors.primary[300]} />
|
||||
) : (
|
||||
<ButtonBase
|
||||
style={{ borderRadius: 999 }}
|
||||
onPress={loadMoreMusicItems}
|
||||
icon={ArrowDown2}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
gap: 2,
|
||||
borderRadius: 10,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
footerContainer: {
|
||||
height: 60,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
export default MusicList;
|
||||
@@ -4,7 +4,6 @@ import { ActivityIndicator, StyleSheet } from 'react-native';
|
||||
import MusicItem, { MusicItemType } from './MusicItem';
|
||||
import ButtonBase from './ButtonBase';
|
||||
import { ArrowDown2, Chart2, ArrowRotateLeft, Cup, Icon } from 'iconsax-react-native';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
// Props type definition for MusicItemTitle.
|
||||
interface MusicItemTitleProps {
|
||||
@@ -19,7 +18,7 @@ interface MusicItemTitleProps {
|
||||
}
|
||||
|
||||
function MusicItemTitleComponent(props: MusicItemTitleProps) {
|
||||
const colorScheme = useColorScheme();
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<Row
|
||||
@@ -41,7 +40,7 @@ function MusicItemTitleComponent(props: MusicItemTitleProps) {
|
||||
{/* Icon with color based on the current color scheme. */}
|
||||
<props.icon
|
||||
size={18}
|
||||
color={colorScheme === 'light' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.7)'}
|
||||
color={colors.text[700]}
|
||||
/>
|
||||
</Row>
|
||||
);
|
||||
@@ -64,12 +63,12 @@ type MusicListProps = {
|
||||
* Function to load more music items asynchronously. Called with current page number
|
||||
* and the list of all music items. Should return a Promise with additional music items.
|
||||
*/
|
||||
loadMoreMusics: (page: number, musics: MusicItemType[]) => Promise<MusicItemType[]>;
|
||||
loadMoreMusics?: (page: number, musics: MusicItemType[]) => Promise<MusicItemType[]>;
|
||||
|
||||
/**
|
||||
* Number of music items to display per page. Determines initial and additional items displayed.
|
||||
*/
|
||||
musicsPerPage: number;
|
||||
musicsPerPage?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -101,23 +100,25 @@ type MusicListProps = {
|
||||
* making it suitable for use cases where the list of items is expected to grow over time.
|
||||
* - The layout and styling are optimized for performance and responsiveness.
|
||||
*/
|
||||
function MusicListComponent({ initialMusics, loadMoreMusics, musicsPerPage }: MusicListProps) {
|
||||
function MusicListComponent({ initialMusics, loadMoreMusics, musicsPerPage = loadMoreMusics ? 50 : initialMusics.length }: MusicListProps) {
|
||||
// State initialization for MusicList.
|
||||
// 'allMusics': all music items.
|
||||
// 'displayedMusics': items displayed per page.
|
||||
// 'currentPage': current page in pagination.
|
||||
// 'loading': indicates if more items are being loaded.
|
||||
// 'hasMoreMusics': flag for more items availability.
|
||||
console.log('initialMusics', initialMusics.length);
|
||||
const [musicListState, setMusicListState] = useState({
|
||||
allMusics: initialMusics,
|
||||
displayedMusics: initialMusics.slice(0, musicsPerPage),
|
||||
currentPage: 1,
|
||||
loading: false,
|
||||
hasMoreMusics: true,
|
||||
hasMoreMusics: initialMusics.length > musicsPerPage || !!loadMoreMusics,
|
||||
});
|
||||
const { colors } = useTheme();
|
||||
const screenSize = useBreakpointValue({ base: 'small', md: 'md', xl: 'xl' });
|
||||
const isBigScreen = screenSize === 'xl';
|
||||
console.log('coucou', initialMusics.length);
|
||||
|
||||
// Loads additional music items.
|
||||
// Uses useCallback to avoid unnecessary redefinitions on re-renders.
|
||||
@@ -132,11 +133,13 @@ function MusicListComponent({ initialMusics, loadMoreMusics, musicsPerPage }: Mu
|
||||
const nextEndIndex = (musicListState.currentPage + 1) * musicsPerPage;
|
||||
let updatedAllMusics = musicListState.allMusics;
|
||||
|
||||
if (updatedAllMusics.length <= nextEndIndex) {
|
||||
if (loadMoreMusics && updatedAllMusics.length <= nextEndIndex) {
|
||||
const newMusics = await loadMoreMusics(musicListState.currentPage, updatedAllMusics);
|
||||
updatedAllMusics = [...updatedAllMusics, ...newMusics];
|
||||
hasMoreMusics = newMusics.length > 0;
|
||||
}
|
||||
} else {
|
||||
hasMoreMusics = updatedAllMusics.length > nextEndIndex;
|
||||
}
|
||||
|
||||
setMusicListState((prevState) => ({
|
||||
...prevState,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import React, { FunctionComponent, ReactNode } from 'react';
|
||||
import { View, StyleSheet } from 'react-native';
|
||||
import { Text, useTheme } from 'native-base';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
line: {
|
||||
@@ -24,15 +23,13 @@ interface SeparatorBaseProps {
|
||||
}
|
||||
|
||||
const SeparatorBase: FunctionComponent<SeparatorBaseProps> = ({ children }) => {
|
||||
const colorScheme = useColorScheme();
|
||||
const { colors } = useTheme();
|
||||
const color = colorScheme === 'light' ? colors.black[500] : '#FFFFFF';
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={[styles.line, { backgroundColor: color }]} />
|
||||
<View style={[styles.line, { backgroundColor: colors.text[700] }]} />
|
||||
<Text style={styles.text}>{children}</Text>
|
||||
<View style={[styles.line, { backgroundColor: color }]} />
|
||||
<View style={[styles.line, { backgroundColor: colors.text[700] }]} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,6 @@ import React, { useState } from 'react';
|
||||
import { View, TouchableOpacity, StyleSheet, StyleProp, ViewStyle } from 'react-native';
|
||||
import InteractiveBase from './InteractiveBase';
|
||||
import { Input, useTheme } from 'native-base';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
export interface TextFieldBaseProps {
|
||||
style?: StyleProp<ViewStyle>;
|
||||
@@ -69,7 +68,6 @@ const TextFieldBase: React.FC<TextFieldBaseProps> = ({
|
||||
const [isFocused, setFocused] = useState(false);
|
||||
const MyIcon: Icon = icon as Icon;
|
||||
const { colors } = useTheme();
|
||||
const colorScheme = useColorScheme();
|
||||
|
||||
const styleAnimate = StyleSheet.create({
|
||||
Default: {
|
||||
@@ -124,9 +122,7 @@ const TextFieldBase: React.FC<TextFieldBaseProps> = ({
|
||||
style={[styles.input, icon ? {} : { paddingLeft: 12 }]}
|
||||
autoComplete={autoComplete}
|
||||
placeholder={placeholder + (isRequired ? '*' : '')}
|
||||
placeholderTextColor={
|
||||
colorScheme === 'light' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.7)'
|
||||
}
|
||||
placeholderTextColor={colors.text[700]}
|
||||
secureTextEntry={isSecret ? !isPasswordVisible : false}
|
||||
onFocus={() => setFocused(true)}
|
||||
onBlur={() => setFocused(false)}
|
||||
|
||||
@@ -11,12 +11,14 @@ import {
|
||||
} from 'react-native-tab-view';
|
||||
import { Heart, Clock, StatusUp, FolderCross } from 'iconsax-react-native';
|
||||
import { Scene } from 'react-native-tab-view/lib/typescript/src/types';
|
||||
import useColorScheme from '../hooks/colorScheme';
|
||||
import { RouteProps } from '../Navigation';
|
||||
import { translate } from '../i18n/i18n';
|
||||
import ScaffoldCC from '../components/UI/ScaffoldCC';
|
||||
import { MusicItemType } from '../components/UI/MusicItem';
|
||||
import MusicList from '../components/UI/MusicList';
|
||||
import { useQueries, useQuery } from '../Queries';
|
||||
import API from '../API';
|
||||
import Song from '../models/Song';
|
||||
import { LoadingView } from '../components/Loading';
|
||||
|
||||
// Fichier de données fictives, par exemple MusicData.ts
|
||||
export const fakeMusicData = [
|
||||
@@ -1159,15 +1161,50 @@ export const fakeMusicData = [
|
||||
];
|
||||
|
||||
export const FavoritesMusic = () => {
|
||||
const playHistoryQuery = useQuery(API.getUserPlayHistory);
|
||||
const nextStepQuery = useQuery(API.getSongSuggestions);
|
||||
const songHistory = useQueries(
|
||||
playHistoryQuery.data?.map(({ songID }) => API.getSong(songID)) ?? []
|
||||
);
|
||||
const artistsQueries = useQueries(
|
||||
songHistory
|
||||
.map((entry) => entry.data)
|
||||
.concat(nextStepQuery.data ?? [])
|
||||
.filter((s): s is Song => s !== undefined)
|
||||
.map((song) => API.getArtist(song.artistId))
|
||||
);
|
||||
|
||||
const isLoading = playHistoryQuery.isLoading || nextStepQuery.isLoading ||
|
||||
songHistory.some(query => query.isLoading) ||
|
||||
artistsQueries.some(query => query.isLoading);
|
||||
|
||||
const musics = nextStepQuery.data
|
||||
?.filter((song) =>
|
||||
artistsQueries.find(
|
||||
(artistQuery) => artistQuery.data?.id === song.artistId
|
||||
)
|
||||
)
|
||||
.map((song) => ({
|
||||
artist: artistsQueries.find(
|
||||
(artistQuery) => artistQuery.data?.id === song.artistId
|
||||
)!.data!.name,
|
||||
song: song.name,
|
||||
image: song.cover,
|
||||
level: 42,
|
||||
lastScore: 42,
|
||||
bestScore: 42,
|
||||
liked: false,
|
||||
onLike: () => {console.log("onLike")},
|
||||
onPlay: () => {console.log("onPlay")},
|
||||
})) ?? []
|
||||
|
||||
if (isLoading) {
|
||||
return <LoadingView />;
|
||||
}
|
||||
return (
|
||||
<MusicList
|
||||
initialMusics={fakeMusicData.slice(0, 20)}
|
||||
musicsPerPage={50}
|
||||
loadMoreMusics={async (page: number, musics: MusicItemType[]) => {
|
||||
const startIndex = musics.length;
|
||||
const endIndex = startIndex + 15;
|
||||
return fakeMusicData.slice(startIndex, Math.min(endIndex, fakeMusicData.length));
|
||||
}}
|
||||
initialMusics={musics}
|
||||
// musicsPerPage={7}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1210,7 +1247,6 @@ const getTabData = (key: string) => {
|
||||
const MusicTab = (props: RouteProps<object>) => {
|
||||
const layout = useWindowDimensions();
|
||||
const [index, setIndex] = React.useState(0);
|
||||
const colorScheme = useColorScheme();
|
||||
const { colors } = useTheme();
|
||||
const screenSize = useBreakpointValue({ base: 'small', md: 'big' });
|
||||
const isSmallScreen = screenSize === 'small';
|
||||
@@ -1229,8 +1265,8 @@ const MusicTab = (props: RouteProps<object>) => {
|
||||
borderBottomWidth: 1,
|
||||
borderColor: colors.primary[300],
|
||||
}}
|
||||
activeColor={colorScheme === 'light' ? '#000' : '#fff'}
|
||||
inactiveColor={colorScheme === 'light' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.7)'}
|
||||
activeColor={colors.text[900]}
|
||||
inactiveColor={colors.text[700]}
|
||||
indicatorStyle={{ backgroundColor: colors.primary[300] }}
|
||||
renderIcon={(
|
||||
scene: Scene<Route> & {
|
||||
@@ -1269,12 +1305,10 @@ const MusicTab = (props: RouteProps<object>) => {
|
||||
sceneContainerStyle={{
|
||||
flex: 1,
|
||||
alignSelf: 'center',
|
||||
padding: isSmallScreen ? 4 : 20,
|
||||
padding: isSmallScreen ? 8 : 20,
|
||||
paddingTop: 32,
|
||||
// maxWidth: 850,
|
||||
width: '100%',
|
||||
}}
|
||||
// style={{ height: 'fit-content' }}
|
||||
renderTabBar={renderTabBar}
|
||||
navigationState={{ index, routes }}
|
||||
renderScene={renderScene}
|
||||
|
||||
@@ -5,11 +5,10 @@ import useUserSettings from '../../hooks/userSettings';
|
||||
import { LoadingView } from '../../components/Loading';
|
||||
import { Calendar1, MonitorMobbile, Send2, Warning2 } from 'iconsax-react-native';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
import { useTheme } from 'native-base';
|
||||
|
||||
const NotificationsSettings = () => {
|
||||
const { settings, updateSettings } = useUserSettings();
|
||||
const colorScheme = useColorScheme();
|
||||
const color = colorScheme === 'light' ? '#000' : '#fff';
|
||||
|
||||
if (!settings.data) {
|
||||
return <LoadingView />;
|
||||
@@ -20,7 +19,7 @@ const NotificationsSettings = () => {
|
||||
elements={[
|
||||
{
|
||||
type: 'toggle',
|
||||
icon: <MonitorMobbile size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: MonitorMobbile,
|
||||
title: translate('SettingsNotificationsTabPushNotificationsSectionTitle'),
|
||||
description: translate(
|
||||
'SettingsNotificationsTabPushNotificationsSectionDescription'
|
||||
@@ -38,7 +37,7 @@ const NotificationsSettings = () => {
|
||||
},
|
||||
{
|
||||
type: 'toggle',
|
||||
icon: <Send2 size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Send2,
|
||||
title: translate('SettingsNotificationsTabEmailNotificationsSectionTitle'),
|
||||
description: translate(
|
||||
'SettingsNotificationsTabEmailNotificationsSectionDescription'
|
||||
@@ -56,7 +55,7 @@ const NotificationsSettings = () => {
|
||||
},
|
||||
{
|
||||
type: 'toggle',
|
||||
icon: <Calendar1 size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Calendar1,
|
||||
title: translate('SettingsNotificationsTabTrainingReminderSectionTitle'),
|
||||
description: translate(
|
||||
'SettingsNotificationsTabTrainingReminderSectionDescription'
|
||||
@@ -74,7 +73,7 @@ const NotificationsSettings = () => {
|
||||
},
|
||||
{
|
||||
type: 'toggle',
|
||||
icon: <Warning2 size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Warning2,
|
||||
title: translate('SettingsNotificationsTabReleaseAlertSectionTitle'),
|
||||
description: translate(
|
||||
'SettingsNotificationsTabReleaseAlertSectionDescription'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { Column } from 'native-base';
|
||||
import { Column, useTheme } from 'native-base';
|
||||
import { useLanguage } from '../../state/LanguageSlice';
|
||||
import { AvailableLanguages, DefaultLanguage, translate } from '../../i18n/i18n';
|
||||
import { useSelector } from '../../state/Store';
|
||||
@@ -8,20 +8,19 @@ import { updateSettings } from '../../state/SettingsSlice';
|
||||
import ElementList from '../../components/GtkUI/ElementList';
|
||||
import LocalSettings from '../../models/LocalSettings';
|
||||
import { Brush2, Colorfilter, LanguageSquare, Rank, Sound } from 'iconsax-react-native';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
const PreferencesSettings = () => {
|
||||
const dispatch = useDispatch();
|
||||
const language = useSelector((state) => state.language.value);
|
||||
const settings = useSelector((state) => state.settings.local);
|
||||
const colorScheme = useColorScheme();
|
||||
const color = colorScheme === 'light' ? '#000' : '#fff';
|
||||
const { colors } = useTheme();
|
||||
|
||||
return (
|
||||
<Column space={4} style={{ width: '100%' }}>
|
||||
<ElementList
|
||||
elements={[
|
||||
{
|
||||
icon: <Brush2 size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Brush2,
|
||||
type: 'dropdown',
|
||||
title: translate('SettingsPreferencesTabThemeSectionTitle'),
|
||||
description: translate('SettingsPreferencesTabThemeSectionDescription'),
|
||||
@@ -43,7 +42,7 @@ const PreferencesSettings = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <LanguageSquare size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: LanguageSquare,
|
||||
type: 'dropdown',
|
||||
title: translate('SettingsPreferencesTabLanguageSectionTitle'),
|
||||
description: translate('SettingsPreferencesTabLanguageSectionDescription'),
|
||||
@@ -61,7 +60,7 @@ const PreferencesSettings = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <Rank size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Rank,
|
||||
type: 'dropdown',
|
||||
title: translate('SettingsPreferencesTabDifficultySectionTitle'),
|
||||
description: translate(
|
||||
@@ -89,7 +88,7 @@ const PreferencesSettings = () => {
|
||||
<ElementList
|
||||
elements={[
|
||||
{
|
||||
icon: <Colorfilter size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Colorfilter,
|
||||
type: 'toggle',
|
||||
title: translate('SettingsPreferencesTabColorblindModeSectionTitle'),
|
||||
description: translate(
|
||||
@@ -107,7 +106,7 @@ const PreferencesSettings = () => {
|
||||
<ElementList
|
||||
elements={[
|
||||
{
|
||||
icon: <Sound size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Sound,
|
||||
type: 'range',
|
||||
title: translate('SettingsPreferencesTabMicVolumeSectionTitle'),
|
||||
description: translate('SettingsPreferencesTabMicVolumeSectionDescription'),
|
||||
|
||||
@@ -7,14 +7,13 @@ import { updateSettings } from '../../state/SettingsSlice';
|
||||
import useUserSettings from '../../hooks/userSettings';
|
||||
import { LoadingView } from '../../components/Loading';
|
||||
import { Driver, Like1, Shop } from 'iconsax-react-native';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
import { useTheme } from 'native-base';
|
||||
|
||||
const PrivacySettings = () => {
|
||||
const dispatch = useDispatch();
|
||||
const settings = useSelector((state: RootState) => state.settings.local);
|
||||
const { settings: userSettings, updateSettings: updateUserSettings } = useUserSettings();
|
||||
const colorScheme = useColorScheme();
|
||||
const color = colorScheme === 'light' ? '#000' : '#fff';
|
||||
const { colors } = useTheme();
|
||||
|
||||
if (!userSettings.data) {
|
||||
return <LoadingView />;
|
||||
@@ -25,7 +24,7 @@ const PrivacySettings = () => {
|
||||
elements={[
|
||||
{
|
||||
type: 'toggle',
|
||||
icon: <Driver size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Driver,
|
||||
title: translate('SettingsPrivacyTabDataCollectionSectionTitle'),
|
||||
description: translate('SettingsPrivacyTabDataCollectionSectionDescription'),
|
||||
data: {
|
||||
@@ -36,7 +35,7 @@ const PrivacySettings = () => {
|
||||
},
|
||||
{
|
||||
type: 'toggle',
|
||||
icon: <Shop size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Shop,
|
||||
title: translate('SettingsPrivacyTabCustomAdsSectionTitle'),
|
||||
description: translate('SettingsPrivacyTabCustomAdsSectionDescription'),
|
||||
data: {
|
||||
@@ -47,7 +46,7 @@ const PrivacySettings = () => {
|
||||
},
|
||||
{
|
||||
type: 'toggle',
|
||||
icon: <Like1 size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Like1,
|
||||
title: translate('SettingsPrivacyTabRecommendationsSectionTitle'),
|
||||
description: translate('SettingsPrivacyTabRecommendationsSectionDescription'),
|
||||
data: {
|
||||
|
||||
@@ -5,7 +5,6 @@ import ElementList from '../../components/GtkUI/ElementList';
|
||||
import { translate } from '../../i18n/i18n';
|
||||
import { useQuery } from '../../Queries';
|
||||
import { Designtools, Magicpen, Star1 } from 'iconsax-react-native';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
|
||||
// Too painful to infer the settings-only, typed navigator. Gave up
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -16,14 +15,12 @@ const PremiumSettings = () => {
|
||||
return <LoadingView />;
|
||||
}
|
||||
const user = userQuery.data;
|
||||
const colorScheme = useColorScheme();
|
||||
const color = colorScheme === 'light' ? '#000' : '#fff';
|
||||
return (
|
||||
<ElementList
|
||||
style={{ width: '100%' }}
|
||||
elements={[
|
||||
{
|
||||
icon: <Star1 size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Star1,
|
||||
type: 'text',
|
||||
title: translate('settingsPremiumTabPremiumAccountSectionTitle'),
|
||||
description: translate('settingsPremiumTabPremiumAccountSectionDescription'),
|
||||
@@ -32,7 +29,7 @@ const PremiumSettings = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <Magicpen size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Magicpen,
|
||||
type: 'toggle',
|
||||
title: translate('settingsPremiumTabPianoMagiqueSectionTitle'),
|
||||
description: translate('settingsPremiumTabPianoMagiqueSectionDescription'),
|
||||
@@ -44,7 +41,7 @@ const PremiumSettings = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <Designtools size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Designtools,
|
||||
type: 'dropdown',
|
||||
title: translate('settingsPremiumTabThemePianoSectionTitle'),
|
||||
description: translate('settingsPremiumTabThemePianoSectionDescription'),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import API from '../../API';
|
||||
import React from 'react';
|
||||
import { Column, Toast } from 'native-base';
|
||||
import { Column, Toast, useTheme } from 'native-base';
|
||||
import { LoadingView } from '../../components/Loading';
|
||||
import ElementList from '../../components/GtkUI/ElementList';
|
||||
import { translate } from '../../i18n/i18n';
|
||||
@@ -31,14 +31,13 @@ const ProfileSettings = () => {
|
||||
return <LoadingView />;
|
||||
}
|
||||
const user = userQuery.data;
|
||||
const colorScheme = useColorScheme();
|
||||
const color = colorScheme === 'light' ? '#000' : '#fff';
|
||||
const { colors } = useTheme();
|
||||
return (
|
||||
<Column space={4} style={{ width: '100%' }}>
|
||||
<ElementList
|
||||
elements={[
|
||||
{
|
||||
icon: <Google size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Google,
|
||||
type: 'text',
|
||||
title: translate('settingsProfileTabGoogleSectionTitle'),
|
||||
description: translate('settingsProfileTabGoogleSectionDescription'),
|
||||
@@ -51,7 +50,7 @@ const ProfileSettings = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <Verify size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: Verify,
|
||||
type: 'text',
|
||||
title: translate('settingsProfileTabVerifiedSectionTitle'),
|
||||
description: translate('settingsProfileTabVerifiedSectionDescription'),
|
||||
@@ -83,7 +82,7 @@ const ProfileSettings = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <UserSquare size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: UserSquare,
|
||||
type: 'text',
|
||||
title: translate('settingsProfileTabAvatarSectionTitle'),
|
||||
description: translate('settingsProfileTabAvatarSectionDescription'),
|
||||
@@ -123,7 +122,7 @@ const ProfileSettings = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <SmsEdit size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: SmsEdit,
|
||||
type: 'sectionDropdown',
|
||||
title: translate('settingsProfileTabChangeEmailSectionTitle'),
|
||||
description: translate('settingsProfileTabChangeEmailSectionDescription'),
|
||||
@@ -138,7 +137,7 @@ const ProfileSettings = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: <PasswordCheck size="24" color={color} style={{ minWidth: 24 }} />,
|
||||
icon: PasswordCheck,
|
||||
type: 'sectionDropdown',
|
||||
title: translate('settingsProfileTabChangePasswordSectionTitle'),
|
||||
description: translate(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Center, Text, useTheme } from 'native-base';
|
||||
import { Center, Text, useBreakpointValue, useTheme } from 'native-base';
|
||||
import ProfileSettings from './SettingsProfile';
|
||||
import NotificationsSettings from './NotificationsSettings';
|
||||
import PrivacySettings from './PrivacySettings';
|
||||
@@ -26,7 +26,6 @@ import { Scene } from 'react-native-tab-view/lib/typescript/src/types';
|
||||
import PremiumSettings from './SettingsPremium';
|
||||
import { RouteProps } from '../../Navigation';
|
||||
import ScaffoldCC from '../../components/UI/ScaffoldCC';
|
||||
import useColorScheme from '../../hooks/colorScheme';
|
||||
import { translate } from '../../i18n/i18n';
|
||||
|
||||
export const PianoSettings = () => {
|
||||
@@ -69,7 +68,6 @@ const getTabData = (key: string) => {
|
||||
const SettingsTab = (props: RouteProps<{}>) => {
|
||||
const layout = useWindowDimensions();
|
||||
const [index, setIndex] = React.useState(0);
|
||||
const colorScheme = useColorScheme();
|
||||
const { colors } = useTheme();
|
||||
const [routes] = React.useState<Route[]>([
|
||||
{ key: 'profile', title: 'settingsTabProfile' },
|
||||
@@ -79,6 +77,8 @@ const SettingsTab = (props: RouteProps<{}>) => {
|
||||
{ key: 'privacy', title: 'settingsTabPrivacy' },
|
||||
{ key: 'piano', title: 'settingsTabPiano' },
|
||||
]);
|
||||
const screenSize = useBreakpointValue({ base: 'small', md: 'big' });
|
||||
const isSmallScreen = screenSize === 'small';
|
||||
const renderTabBar = (
|
||||
props: SceneRendererProps & { navigationState: NavigationState<Route> }
|
||||
) => (
|
||||
@@ -89,8 +89,8 @@ const SettingsTab = (props: RouteProps<{}>) => {
|
||||
borderBottomWidth: 1,
|
||||
borderColor: colors.primary[300],
|
||||
}}
|
||||
activeColor={colorScheme === 'light' ? '#000' : '#fff'}
|
||||
inactiveColor={colorScheme === 'light' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.7)'}
|
||||
activeColor={colors.text[900]}
|
||||
inactiveColor={colors.text[700]}
|
||||
indicatorStyle={{ backgroundColor: colors.primary[300] }}
|
||||
renderIcon={(
|
||||
scene: Scene<Route> & {
|
||||
@@ -133,7 +133,7 @@ const SettingsTab = (props: RouteProps<{}>) => {
|
||||
flex: 1,
|
||||
alignSelf: 'center',
|
||||
paddingTop: 32,
|
||||
padding: 20,
|
||||
padding: isSmallScreen ? 8 : 20,
|
||||
maxWidth: 850,
|
||||
width: '100%',
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user