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 })}