From 56bd5a9ecdc1b792bf31f86fc992c6db1f6424df Mon Sep 17 00:00:00 2001 From: Luca Pezzolla Date: Tue, 21 Nov 2023 12:33:43 +0100 Subject: [PATCH] feat: add screen for accessibility settings WIP Refs #368 --- assets/translations/en.json | 12 ++ assets/translations/it.json | 12 ++ lib/ui/components/ListItem.tsx | 3 +- lib/ui/components/Metric.tsx | 2 +- lib/ui/components/Text.tsx | 10 +- src/core/contexts/PreferencesContext.ts | 32 ++-- .../user/components/UserNavigator.tsx | 10 ++ .../screens/AccessibilitySettingsScreen.tsx | 160 ++++++++++++++++++ src/features/user/screens/SettingsScreen.tsx | 11 ++ 9 files changed, 234 insertions(+), 18 deletions(-) create mode 100644 src/features/user/screens/AccessibilitySettingsScreen.tsx diff --git a/assets/translations/en.json b/assets/translations/en.json index a4e19efc..f06db48c 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -1,4 +1,15 @@ { + "accessibilitySettingsScreen": { + "title": "Accessibility settings", + "customFontTitle": "Custom font", + "customFontAction": "Pick a font", + "customFontPlacement": "Use it for", + "themeCustomizationTitle": "Theme customization", + "customFontSectionTitle": "Accessible font", + "customThemeSectionTitle": "Accessible theme", + "highContrastTitle": "High contrast", + "greyscaleTitle": "Greyscale" + }, "agendaScreen": { "backToToday": "Back to today", "dailyLayout": "Daily layout", @@ -73,6 +84,7 @@ "yellow": "Yellow" }, "common": { + "accessibility": "Accessibility", "actionPotentiallyNotUndoable": "This action may not be undoable", "activeStatus": { "false": "Non active", diff --git a/assets/translations/it.json b/assets/translations/it.json index 44fff0f8..9bc4003b 100644 --- a/assets/translations/it.json +++ b/assets/translations/it.json @@ -1,4 +1,15 @@ { + "accessibilitySettingsScreen": { + "title": "Impostazioni di accessibilità", + "customFontTitle": "Font personalizzato", + "customFontDefault": "No custom font", + "customFontAction": "Seleziona un font", + "customFontPlacement": "Usalo per", + "customFontSectionTitle": "Font accessibile", + "customThemeSectionTitle": "Tema accessibile", + "highContrastTitle": "Alto contrasto", + "greyscaleTitle": "Scala di grigi" + }, "agendaScreen": { "backToToday": "Torna a oggi", "dailyLayout": "Layout giornaliero", @@ -73,6 +84,7 @@ "yellow": "Giallo" }, "common": { + "accessibility": "Accessibilità", "actionPotentiallyNotUndoable": "Questa azione potrebbe non essere annullabile", "activeStatus": { "false": "Non attiva", diff --git a/lib/ui/components/ListItem.tsx b/lib/ui/components/ListItem.tsx index c552c119..2df08fcd 100644 --- a/lib/ui/components/ListItem.tsx +++ b/lib/ui/components/ListItem.tsx @@ -1,6 +1,5 @@ import { StyleProp, - TextProps, TextStyle, TouchableHighlight, TouchableHighlightProps, @@ -20,7 +19,7 @@ import { GlobalStyles } from '../../../src/core/styles/GlobalStyles'; import { resolveLinkTo } from '../../../src/utils/resolveLinkTo'; import { useTheme } from '../hooks/useTheme'; import { DisclosureIndicator } from './DisclosureIndicator'; -import { Text } from './Text'; +import { Text, TextProps } from './Text'; export interface ListItemProps extends TouchableHighlightProps { title: string | JSX.Element; diff --git a/lib/ui/components/Metric.tsx b/lib/ui/components/Metric.tsx index 07bb4e38..6113418f 100644 --- a/lib/ui/components/Metric.tsx +++ b/lib/ui/components/Metric.tsx @@ -2,7 +2,7 @@ import { View, ViewProps } from 'react-native'; import { useTheme } from '../hooks/useTheme'; import { CardProps } from './Card'; -import { Text, Props as TextProps } from './Text'; +import { Text, TextProps } from './Text'; type Props = ViewProps & { title: string; diff --git a/lib/ui/components/Text.tsx b/lib/ui/components/Text.tsx index 906643bd..73f14ff3 100644 --- a/lib/ui/components/Text.tsx +++ b/lib/ui/components/Text.tsx @@ -1,10 +1,14 @@ -import { Text as RNText, StyleSheet, TextProps } from 'react-native'; +import { + Text as RNText, + TextProps as RNTextProps, + StyleSheet, +} from 'react-native'; import { useStylesheet } from '../hooks/useStylesheet'; import { useTheme } from '../hooks/useTheme'; import { Theme } from '../types/Theme'; -export interface Props extends TextProps { +export interface TextProps extends RNTextProps { variant?: | 'heading' | 'subHeading' @@ -45,7 +49,7 @@ export const Text = ({ uppercase, children, ...rest -}: Props) => { +}: TextProps) => { const { colors, fontFamilies, fontWeights } = useTheme(); const styles = useStylesheet(createStyles); const fontFamilyName = diff --git a/src/core/contexts/PreferencesContext.ts b/src/core/contexts/PreferencesContext.ts index 76ca597a..fa3b141d 100644 --- a/src/core/contexts/PreferencesContext.ts +++ b/src/core/contexts/PreferencesContext.ts @@ -7,35 +7,37 @@ import { AgendaTypesFilterState } from '../../features/agenda/types/AgendaTypesF import { UnreadNotifications } from '../types/notifications'; export const editablePreferenceKeys = [ - 'lastInstalledVersion', - 'username', + 'accessibility', + 'agendaScreen', 'campusId', 'colorScheme', 'courses', + 'emailGuideRead', + 'favoriteServices', 'language', + 'lastInstalledVersion', 'notifications', - 'favoriteServices', - 'peopleSearched', - 'unreadNotifications', 'onboardingStep', - 'emailGuideRead', + 'peopleSearched', 'placesSearched', - 'agendaScreen', + 'unreadNotifications', + 'username', ] as const; export type PreferenceKey = typeof editablePreferenceKeys[number]; // Specify here complex keys, that require serialization/deserialization export const objectPreferenceKeys = [ + 'accessibility', + 'agendaScreen', 'courses', - 'notifications', + 'emailGuideRead', 'favoriteServices', - 'peopleSearched', - 'unreadNotifications', + 'notifications', 'onboardingStep', - 'emailGuideRead', + 'peopleSearched', 'placesSearched', - 'agendaScreen', + 'unreadNotifications', ]; export type CoursesPreferences = { @@ -74,6 +76,12 @@ export interface PreferencesContextBase { layout: 'weekly' | 'daily'; filters: AgendaTypesFilterState; }; + accessibility?: { + fontFamily?: 'default' | 'open-dyslexic'; + fontPlacement?: 'default' | 'bottom'; + highContrast?: boolean; + grayscale?: boolean; + }; } export interface PreferencesContextProps extends PreferencesContextBase { diff --git a/src/features/user/components/UserNavigator.tsx b/src/features/user/components/UserNavigator.tsx index 120198cf..d4823438 100644 --- a/src/features/user/components/UserNavigator.tsx +++ b/src/features/user/components/UserNavigator.tsx @@ -9,6 +9,7 @@ import { useTitlesStyles } from '../../../core/hooks/useTitlesStyles'; import { SharedScreens } from '../../../shared/navigation/SharedScreens'; import { DegreeTopTabsNavigator } from '../../offering/navigation/DegreeTopTabsNavigator'; import { OfferingStackParamList } from '../../services/components/ServicesNavigator'; +import { AccessibilitySettingsScreen } from '../screens/AccessibilitySettingsScreen'; import { MessageScreen } from '../screens/MessageScreen'; import { MessagesScreen } from '../screens/MessagesScreen'; import { ProfileScreen } from '../screens/ProfileScreen'; @@ -17,6 +18,7 @@ import { SettingsScreen } from '../screens/SettingsScreen'; export type UserStackParamList = OfferingStackParamList & { Profile: undefined; Settings: undefined; + AccessibilitySettings: undefined; Messages: undefined; Message: { id: number; @@ -59,6 +61,14 @@ export const UserNavigator = () => { headerTitle: t('settingsScreen.title'), }} /> + void; +} + +export const AccessibilitySettingsScreen = () => { + const { t } = useTranslation(); + const { accessibility } = usePreferencesContext(); + + return ( + + + +
+ + + + + +
+
+ + + { + // TODO + }} + /> + { + // TODO + }} + /> + +
+ + +
+
+ ); +}; + +const CustomFontListItem = ({ t, value }: AccessibilityItemProps) => { + const choices = useMemo(() => { + return [ + 'Montserrat (default)', + 'Open Dyslexic', + 'Dyslexie', + 'EasyReading', + 'Sylexiad', + ]; + }, []); + + const effectiveValue = useMemo(() => { + return value || 'default'; + }, [value]); + + const actions: MenuAction[] = useMemo(() => { + return choices.map(cc => { + const actionValue = cc.endsWith('(default)') ? 'default' : cc; + return { + id: actionValue, + title: cc, + state: actionValue === effectiveValue ? 'on' : undefined, + }; + }); + }, [effectiveValue, choices]); + + return ( + { + // onUpdate(effectiveValue); + }} + > + + + ); +}; + +const CustomFontPlacementListItem = ({ t, value }: AccessibilityItemProps) => { + const choices = useMemo(() => { + // places in which to use the custom font for accessibility + return ['None', 'Long text', 'All text']; + }, []); + + const effectiveValue = useMemo(() => { + return value || 'none'; + }, [value]); + + const effectiveLabel = useMemo(() => { + return effectiveValue.replace('-', ' '); + }, [effectiveValue]); + + const actions: MenuAction[] = useMemo(() => { + return choices.map(cc => { + const choiceId = cc.toLowerCase().replace(' ', '-'); + return { + id: choiceId, + title: cc, + state: choiceId === effectiveValue ? 'on' : undefined, + }; + }); + }, [effectiveValue, choices]); + + return ( + { + // onUpdate(effectiveValue); + }} + > + + + ); +}; diff --git a/src/features/user/screens/SettingsScreen.tsx b/src/features/user/screens/SettingsScreen.tsx index b3827ed3..e2929322 100644 --- a/src/features/user/screens/SettingsScreen.tsx +++ b/src/features/user/screens/SettingsScreen.tsx @@ -327,6 +327,17 @@ export const SettingsScreen = () => { +
+ + + + +
{t('settingsScreen.appVersion', { version })}