mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-03 08:06:59 +00:00
Merge branch 'cu-readx' into catch-up-2026-11
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import { View } from 'react-native';
|
||||
import { Platform, View } from 'react-native';
|
||||
import { SettingsSection, SettingItem, Select, ToggleSwitch } from './settings-section';
|
||||
import Button from '../Button';
|
||||
import { spacing } from '../../theme/tokens';
|
||||
import { useLocaleStore } from '../../stores/locale-store';
|
||||
import { FONT_SIZES, useSettingsStore, type FontSize } from '../../stores/settings-store';
|
||||
import { APP_FONTS, FONT_SIZES, useSettingsStore, type AppFont, type FontSize } from '../../stores/settings-store';
|
||||
import { uiFontsBundled } from '../../theme/reading-fonts';
|
||||
import { toast } from '../../stores/toast-store';
|
||||
import {
|
||||
ACCESSIBILITY_PRESET_IDS,
|
||||
@@ -15,6 +16,14 @@ import {
|
||||
} from '../../lib/accessibility-presets';
|
||||
import { TOAST_DURATION_CHOICES } from '../../lib/toast-duration';
|
||||
|
||||
// Font names are names: the same in every language (webmail
|
||||
// accessibility-settings.tsx).
|
||||
const FONT_NAMES: Record<Exclude<AppFont, 'default'>, string> = {
|
||||
atkinson: 'Atkinson Hyperlegible',
|
||||
lexend: 'Lexend',
|
||||
opendyslexic: 'OpenDyslexic',
|
||||
};
|
||||
|
||||
// Percentages read the same in every language the app has.
|
||||
const TEXT_SIZE_LABELS: Record<FontSize, string> = {
|
||||
small: '87.5%',
|
||||
@@ -41,6 +50,11 @@ function presetCopy(id: AccessibilityPresetId, t: Translate): { label: string; d
|
||||
label: t('settings.accessibility.presets.low-vision.label', 'Low vision'),
|
||||
description: t('settings.accessibility.presets.low-vision.description_mobile', 'Text at 150% and labels under the toolbar icons.'),
|
||||
};
|
||||
case 'dyslexia':
|
||||
return {
|
||||
label: t('settings.accessibility.presets.dyslexia.label', 'Dyslexia'),
|
||||
description: t('settings.accessibility.presets.dyslexia.description_mobile', 'Atkinson Hyperlegible as the font, also for plain-text messages.'),
|
||||
};
|
||||
case 'motion':
|
||||
return {
|
||||
label: t('settings.accessibility.presets.motion.label', 'Motion and seizure safe'),
|
||||
@@ -61,6 +75,9 @@ export function AccessibilitySettings() {
|
||||
const hydrate = useSettingsStore((s) => s.hydrate);
|
||||
const update = useSettingsStore((s) => s.updateSetting);
|
||||
const fontSize = useSettingsStore((s) => s.fontSize);
|
||||
const appFont = useSettingsStore((s) => s.appFont);
|
||||
const colorBlindPalette = useSettingsStore((s) => s.colorBlindPalette);
|
||||
const plainLanguage = useSettingsStore((s) => s.plainLanguage);
|
||||
const animationsEnabled = useSettingsStore((s) => s.animationsEnabled);
|
||||
const toastDuration = useSettingsStore((s) => s.toastDuration);
|
||||
const sendConfirmation = useSettingsStore((s) => s.sendConfirmation);
|
||||
@@ -130,7 +147,6 @@ export function AccessibilitySettings() {
|
||||
<SettingItem
|
||||
label={t('settings.accessibility.text_size.label', 'Text size')}
|
||||
description={t('settings.accessibility.text_size.description_mobile', "Scales the app's text on top of your phone's text size. 100% is your phone's size.")}
|
||||
noBorder
|
||||
>
|
||||
<Select
|
||||
value={fontSize}
|
||||
@@ -138,6 +154,46 @@ export function AccessibilitySettings() {
|
||||
options={FONT_SIZES.map((size) => ({ value: size, label: TEXT_SIZE_LABELS[size] }))}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
label={t('settings.accessibility.font.label', 'Font')}
|
||||
description={uiFontsBundled(Platform.OS)
|
||||
? t('settings.accessibility.font.description', 'Atkinson Hyperlegible and Lexend are designed to be easy to tell apart; OpenDyslexic helps some people with dyslexia. They cover Latin script.')
|
||||
: t('settings.accessibility.font.description_ios', 'Atkinson Hyperlegible and Lexend are designed to be easy to tell apart; OpenDyslexic helps some people with dyslexia. On this device the font is used for plain-text messages.')}
|
||||
>
|
||||
<Select
|
||||
value={appFont}
|
||||
onChange={(v) => update('appFont', v as AppFont)}
|
||||
options={APP_FONTS.map((font) => ({
|
||||
value: font,
|
||||
label: font === 'default' ? t('settings.accessibility.font.default', 'Theme font') : FONT_NAMES[font],
|
||||
}))}
|
||||
/>
|
||||
</SettingItem>
|
||||
<SettingItem
|
||||
label={t('settings.accessibility.plain_language.label', 'Plain language')}
|
||||
description={t('settings.accessibility.plain_language.description_mobile', 'Simpler wording for settings and error messages. Available in English and German.')}
|
||||
noBorder
|
||||
>
|
||||
<ToggleSwitch
|
||||
checked={plainLanguage}
|
||||
onChange={(v) => update('plainLanguage', v)}
|
||||
accessibilityLabel={t('settings.accessibility.plain_language.label', 'Plain language')}
|
||||
/>
|
||||
</SettingItem>
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection title={t('settings.accessibility.sections.contrast', 'Colour and contrast')}>
|
||||
<SettingItem
|
||||
label={t('settings.accessibility.cvd_palette.label', 'Colour-blind-safe colours')}
|
||||
description={t('settings.accessibility.cvd_palette.description_mobile', 'Uses tag and calendar colours that stay distinct with red-green or blue-yellow colour blindness.')}
|
||||
noBorder
|
||||
>
|
||||
<ToggleSwitch
|
||||
checked={colorBlindPalette}
|
||||
onChange={(v) => update('colorBlindPalette', v)}
|
||||
accessibilityLabel={t('settings.accessibility.cvd_palette.label', 'Colour-blind-safe colours')}
|
||||
/>
|
||||
</SettingItem>
|
||||
</SettingsSection>
|
||||
|
||||
<SettingsSection title={t('settings.accessibility.sections.motion', 'Motion')}>
|
||||
|
||||
@@ -113,7 +113,7 @@ export function KeywordSettings() {
|
||||
/>
|
||||
);
|
||||
}
|
||||
const palette = c.tags[kw.color];
|
||||
const palette = (c.tagsAsPicked ?? c.tags)[kw.color];
|
||||
return (
|
||||
<View key={kw.id} style={styles.kwRow}>
|
||||
<View style={[styles.kwDot, { backgroundColor: palette.dot }]} />
|
||||
@@ -178,7 +178,7 @@ export function KeywordSettings() {
|
||||
</Text>
|
||||
{scan.found.map((kw) => (
|
||||
<View key={kw.id} style={styles.kwRow}>
|
||||
<View style={[styles.kwDot, { backgroundColor: c.tags[kw.color]?.dot ?? c.textMuted }]} />
|
||||
<View style={[styles.kwDot, { backgroundColor: (c.tagsAsPicked ?? c.tags)[kw.color]?.dot ?? c.textMuted }]} />
|
||||
<View style={{ flex: 1 }}>
|
||||
<Text style={styles.kwLabel}>{kw.label}</Text>
|
||||
<Text style={styles.kwId}>{kw.keyword} · {kw.count}</Text>
|
||||
@@ -251,7 +251,7 @@ function SharedTagsSection() {
|
||||
) : (
|
||||
tags.map((kw) => (
|
||||
<View key={kw.id} style={styles.kwRow}>
|
||||
<View style={[styles.kwDot, { backgroundColor: c.tags[kw.color]?.dot ?? c.textMuted }]} />
|
||||
<View style={[styles.kwDot, { backgroundColor: (c.tagsAsPicked ?? c.tags)[kw.color]?.dot ?? c.textMuted }]} />
|
||||
<Text style={styles.kwLabel}>{kw.label}</Text>
|
||||
<Text style={styles.kwId}>$label:{kw.id}</Text>
|
||||
</View>
|
||||
@@ -313,7 +313,9 @@ function KeywordForm({ initial, existingIds, onSave, onCancel }: KeywordFormProp
|
||||
<Text style={styles.formLabel}>{t('settings.keywords.color_field', "Color")}</Text>
|
||||
<View style={styles.palette}>
|
||||
{PALETTE_KEYS.map((key) => {
|
||||
const p = c.tags[key];
|
||||
// The colours as picked, also with colour-blind-safe colours on
|
||||
// (webmail keyword-settings.tsx draws KEYWORD_PALETTE).
|
||||
const p = (c.tagsAsPicked ?? c.tags)[key];
|
||||
return (
|
||||
<Pressable
|
||||
key={key}
|
||||
|
||||
Reference in New Issue
Block a user