diff --git a/assets/translations/en.json b/assets/translations/en.json index 47129dae..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", @@ -12,6 +23,12 @@ }, "bookingScreen": { "barCodeTitle": "Barcode", + "bookingStatus": { + "available": "Available", + "booked": "Booked", + "full": "Full", + "notAvailable": "Not available" + }, "cancelBooking": "Cancel booking", "cancelBookingText": "Are you sure you want to cancel this booking?", "cancelFeedback": "Booking canceled", @@ -21,35 +38,29 @@ "locationType": { "place": "Place", "virtualPlace": "Link virtual place" - }, - "bookingStatus": { - "notAvailable": "Not available", - "available": "Available", - "booked": "Booked", - "full": "Full" } }, - "bookingsScreen": { - "emptyState": "You have no active bookings", - "newBooking": "New booking", - "sectionTitle": "Active", - "title": "Bookings" - }, "bookingSeatScreen": { - "title": "Select a seat", - "noSeatsAvailable": "We're sorry,\nthere are no places available", - "deadlineExpired": "We're sorry,\nthe deadline to book for this round has passed", - "slotBookableFrom": "This slot will be bookable starting from ", "confirm": "Confirm booking", + "deadlineExpired": "We're sorry,\nthe deadline to book for this round has passed", "informationAcknowledgment": "I declare that I have read it\nof the ", "informationAcknowledgmentLink": "COVID 19 emergency information", "noSeatSelected": "No seat", - "zoomInToEnableSeatSelection": "Zoom in to enable seat selection", + "noSeatsAvailable": "We're sorry,\nthere are no places available", "seatStatus": { - "booked": "Booked", "available": "Available", + "booked": "Booked", "notAvailable": "Non bookable" - } + }, + "slotBookableFrom": "This slot will be bookable starting from ", + "title": "Select a seat", + "zoomInToEnableSeatSelection": "Zoom in to enable seat selection" + }, + "bookingsScreen": { + "emptyState": "You have no active bookings", + "newBooking": "New booking", + "sectionTitle": "Active", + "title": "Bookings" }, "colors": { "amber": "Amber", @@ -73,25 +84,17 @@ "yellow": "Yellow" }, "common": { - "back": "Back", - "desk": "Desk", - "seat": "Seat", - "reset": "Reset", - "hour": "Hour", - "day": "Day", + "accessibility": "Accessibility", "actionPotentiallyNotUndoable": "This action may not be undoable", "activeStatus": { "false": "Non active", "true": "Active" }, "agent": "Agent", - "legend": "Legend", - "close": "Close", - "search": "Search", - "cfu": "CFU", "all": "All", "appFeedback": "App Feedback", "areYouSure?": "Are you sure?", + "back": "Back", "booking": "Booking", "booking_plural": "Bookings", "building": "Building", @@ -101,8 +104,10 @@ "campus": "Campus", "cancel": "Cancel", "capacity": "Capacity", + "cfu": "CFU", "classroomsNotSpecified": "Classroom not specified", "cleanCourseFiles": "Remove all course files", + "close": "Close", "color": "Color", "comingSoon": "Coming soon", "confirm": "Confirm", @@ -115,10 +120,12 @@ "creditsWithoutUnit": "{{credits}}", "dateAndHours": "Date and hour", "dateToBeDefined": "Date to be defined", + "day": "Day", "deadline": "Deadline", "deadline_plural": "Deadlines", "delete": "Delete", "department": "Department", + "desk": "Desk", "done": "Done", "doubleClickToSeeLinks": "Tap twice to see links", "doubleTapToActive": "Tap twice to activate", @@ -162,6 +169,7 @@ "follow": "Follow", "free": "Free", "grade": "Grade", + "hour": "Hour", "hours": "Hour", "icon": "Icon", "inYourAgenda": "in your agenda", @@ -169,6 +177,7 @@ "language": "Language", "lecture": "Lecture", "lecture_plural": "Lectures", + "legend": "Legend", "loading": "Loading", "location": "Location", "logout": "Logout", @@ -178,6 +187,7 @@ "newItems_plural": "New items", "next": "Next", "noInternet": "You are offline, some features may not be available", + "noValue": "No value", "notFound": "Not found", "notes": "Notes", "notice": "Notice", @@ -210,9 +220,12 @@ "recentlyViewed": "Recently viewed", "refresh": "Refresh", "remove": "Remove", + "reset": "Reset", "retract": "Retract", "roleCollaborator": "Collaborator", "roleHolder": "Holder", + "search": "Search", + "seat": "Seat", "selectAnOption": "Please select an option", "services": "Services", "somethingWentWrong": "Something went wrong, try again later", @@ -428,7 +441,8 @@ "title": "Guide" }, "guidesScreen": { - "title": "Guides" + "title": "Guides", + "total": "There are {{total}} guides" }, "jobOfferScreen": { "application": "Application", diff --git a/assets/translations/it.json b/assets/translations/it.json index 6249ef1a..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", @@ -12,6 +23,12 @@ }, "bookingScreen": { "barCodeTitle": "Barcode", + "bookingStatus": { + "available": "Prenotabile", + "booked": "Prenotato", + "full": "Non prenotabile", + "notAvailable": "Non ancora prenotabile" + }, "cancelBooking": "Annulla prenotazione", "cancelBookingText": "Sei sicuro di voler annullare la prenotazione?", "cancelFeedback": "Prenotazione annullata", @@ -21,35 +38,29 @@ "locationType": { "place": "Luogo", "virtualPlace": "Link sportello virtuale" - }, - "bookingStatus": { - "notAvailable": "Non ancora prenotabile", - "available": "Prenotabile", - "booked": "Prenotato", - "full": "Non prenotabile" } }, - "bookingsScreen": { - "emptyState": "Non hai prenotazioni attive", - "newBooking": "Nuova prenotazione", - "sectionTitle": "Attive", - "title": "Prenotazioni" - }, "bookingSeatScreen": { - "title": "Scegli il posto", - "noSeatsAvailable": "Siamo spiacenti,\nnon ci sono posti disponibili", - "deadlineExpired": "Siamo spiacenti,\nè scaduto il termine ultimo per potersi prenotare a questo turno", - "slotBookableFrom": "Questo slot sarà prenotabile a partire dal ", "confirm": "Conferma prenotazione", + "deadlineExpired": "Siamo spiacenti,\nè scaduto il termine ultimo per potersi prenotare a questo turno", "informationAcknowledgment": "Dichiaro di aver preso visione \ndell' ", "informationAcknowledgmentLink": "Informativa emergenza COVID 19", "noSeatSelected": "Nessuna", - "zoomInToEnableSeatSelection": "Zoom in per abilitare la selezione del posto", + "noSeatsAvailable": "Siamo spiacenti,\nnon ci sono posti disponibili", "seatStatus": { - "booked": "Prenotato", "available": "Disponibile", + "booked": "Prenotato", "notAvailable": "Non prenotabile" - } + }, + "slotBookableFrom": "Questo slot sarà prenotabile a partire dal ", + "title": "Scegli il posto", + "zoomInToEnableSeatSelection": "Zoom in per abilitare la selezione del posto" + }, + "bookingsScreen": { + "emptyState": "Non hai prenotazioni attive", + "newBooking": "Nuova prenotazione", + "sectionTitle": "Attive", + "title": "Prenotazioni" }, "colors": { "amber": "Ambra", @@ -73,23 +84,13 @@ "yellow": "Giallo" }, "common": { - "desk": "Cattedra", - "seat": "Postazione", - "reset": "Reimposta", - "hour": "Orario", - "day": "Giorno", - "other": "Altro", - "noValue": "Nessun valore", + "accessibility": "Accessibilità", "actionPotentiallyNotUndoable": "Questa azione potrebbe non essere annullabile", "activeStatus": { "false": "Non attiva", "true": "Attiva" }, "agent": "Operatore", - "legend": "Legenda", - "close": "Chiudi", - "search": "Cerca", - "cfu": "CFU", "all": "Tutti", "appFeedback": "Segnalazioni App", "areYouSure?": "Sei sicuro?", @@ -103,8 +104,10 @@ "campus": "Sede", "cancel": "Annulla", "capacity": "Capacità", + "cfu": "CFU", "classroomsNotSpecified": "Luogo non specificato", "cleanCourseFiles": "Rimuovi file dei corsi", + "close": "Chiudi", "color": "Colore", "comingSoon": "Coming soon", "confirm": "Conferma", @@ -117,10 +120,12 @@ "creditsWithoutUnit": "{{credits}}", "dateAndHours": "Data e ora", "dateToBeDefined": "Data da definire", + "day": "Giorno", "deadline": "Scadenza", "deadline_plural": "Scadenze", "delete": "Elimina", "department": "Dipartimento", + "desk": "Cattedra", "done": "Fatto", "doubleClickToSeeLinks": "Premi due volte per vedere i link", "doubleTapToActive": "Doppio tocco per attivare", @@ -164,6 +169,7 @@ "follow": "Segui", "free": "Libera", "grade": "Voto", + "hour": "Orario", "hours": "Ore", "icon": "Icona", "inYourAgenda": "nella tua agenda", @@ -171,6 +177,7 @@ "language": "Lingua", "lecture": "Lezione", "lecture_plural": "Lezioni", + "legend": "Legenda", "loading": "Caricamento", "location": "Sede", "logout": "Logout", @@ -180,6 +187,7 @@ "newItems_plural": "Nuovi elementi", "next": "Avanti", "noInternet": "Sei offline, alcune funzionalità potrebbero non essere disponibili", + "noValue": "Nessun valore", "notFound": "Luogo inesistente", "notes": "Note", "notice": "Avviso", @@ -201,6 +209,7 @@ "true": "Doppio click per chiudere" }, "options": "Opzioni", + "other": "Altro", "pause": "Pausa", "period": "Semestre", "phone": "Telefono", @@ -211,9 +220,12 @@ "recentlyViewed": "Visto di recente", "refresh": "Aggiorna", "remove": "Rimuovi", + "reset": "Reimposta", "retract": "Ritira", "roleCollaborator": "Collaboratore", "roleHolder": "Titolare", + "search": "Cerca", + "seat": "Postazione", "selectAnOption": "Seleziona una delle opzioni", "services": "Servizi", "somethingWentWrong": "Qualcosa è andato storto, riprova più tardi", 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 })}