mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-03 16:07:32 +00:00
feat: show calendar events in light tinted colours on request
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Pressable, StyleSheet, Text, View, type StyleProp, type ViewStyle } from 'react-native';
|
||||
import type { EventBlockColors } from '../../lib/event-colors';
|
||||
import { TINTED_BAR_WIDTH, type EventBlockColors } from '../../lib/event-colors';
|
||||
|
||||
// Events in the week and day grids, shared by the paged WeekView and the
|
||||
// scrolling TimeGridScrollView. Every event is a solid block of its calendar
|
||||
@@ -80,9 +80,11 @@ export function TimedEventBlock({
|
||||
styles.block,
|
||||
corners('vertical', continuesBefore, continuesAfter, EVENT_RADIUS),
|
||||
{ backgroundColor: colors.fill, borderColor: ringColor },
|
||||
colors.bar ? styles.blockWithBar : null,
|
||||
style,
|
||||
]}
|
||||
>
|
||||
{colors.bar ? <View pointerEvents="none" style={[styles.startBar, { backgroundColor: colors.bar }]} /> : null}
|
||||
{inactive && (
|
||||
// The calendar-coloured outline sits inside the ring.
|
||||
<View
|
||||
@@ -143,10 +145,12 @@ export function AllDayEventBar({
|
||||
styles.bar,
|
||||
corners('horizontal', continuesBefore, continuesAfter, EVENT_RADIUS),
|
||||
{ backgroundColor: colors.fill },
|
||||
colors.bar ? styles.barWithBar : null,
|
||||
inactive && [styles.barInactive, { borderColor: colors.border ?? undefined }],
|
||||
style,
|
||||
]}
|
||||
>
|
||||
{colors.bar ? <View pointerEvents="none" style={[styles.startBar, { backgroundColor: colors.bar }]} /> : null}
|
||||
<Text style={[styles.barTitle, { color: colors.text }]} numberOfLines={1}>
|
||||
{continuesBefore ? '… ' : ''}
|
||||
<Text style={inactive && styles.struck}>{title}</Text>
|
||||
@@ -164,6 +168,11 @@ const styles = StyleSheet.create({
|
||||
overflow: 'hidden',
|
||||
},
|
||||
outline: { ...StyleSheet.absoluteFillObject, borderWidth: 1 },
|
||||
// The title clears the light style's bar.
|
||||
blockWithBar: { paddingStart: 3 + TINTED_BAR_WIDTH },
|
||||
barWithBar: { paddingStart: 4 + TINTED_BAR_WIDTH },
|
||||
// "Light event colors": the calendar colour along the start edge.
|
||||
startBar: { position: 'absolute', top: 0, bottom: 0, start: 0, width: TINTED_BAR_WIDTH },
|
||||
blockTitle: { fontSize: 12, lineHeight: 15, fontWeight: '500' },
|
||||
blockTime: { fontSize: 10.5, lineHeight: 13, fontWeight: '400', opacity: 0.85 },
|
||||
struck: { textDecorationLine: 'line-through' },
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import type { Calendar, CalendarEvent } from '../../api/types';
|
||||
import { componentSizes, spacing, typography, type ThemePalette } from '../../theme/tokens';
|
||||
import { useColors } from '../../theme/colors';
|
||||
import { useSettingsStore } from '../../stores/settings-store';
|
||||
import {
|
||||
buildEventDayIndex,
|
||||
eventsOnDayFromIndex,
|
||||
@@ -26,7 +27,7 @@ import {
|
||||
} from '../../lib/calendar-utils';
|
||||
import { dayIndexIn, monthChipShowsTime, monthKeyOf, monthMask } from '../../lib/calendar-month-scroll';
|
||||
import { isInactiveEvent } from '../../lib/calendar-participants';
|
||||
import { eventBlockColors } from '../../lib/event-colors';
|
||||
import { TINTED_BAR_WIDTH, eventBlockColors } from '../../lib/event-colors';
|
||||
import { useCalendarLocale } from '../../lib/calendar-locale';
|
||||
import { dayCellAccessibilityLabel } from '../../lib/calendar-a11y';
|
||||
import { displayNow } from '../../lib/calendar-timezone';
|
||||
@@ -156,6 +157,8 @@ function MonthWeekRowInner({
|
||||
const c = useColors();
|
||||
const { t } = useCalendarLocale();
|
||||
const { width } = useWindowDimensions();
|
||||
// "Light event colors" (webmail calendarTintedEvents).
|
||||
const tinted = useSettingsStore((s) => s.calendarTintedEvents);
|
||||
const chipTime = monthChipShowsTime(true, width / 7);
|
||||
if (variant === 'full') {
|
||||
return (
|
||||
@@ -254,13 +257,14 @@ function MonthWeekRowInner({
|
||||
// Solid bars in the calendar colour; declined and
|
||||
// cancelled events outlined (repos/branding/APP.md).
|
||||
const inactive = isInactiveEvent(event, currentUserEmails);
|
||||
const colors = eventBlockColors(getEventColor(event, calendars), inactive, c);
|
||||
const colors = eventBlockColors(getEventColor(event, calendars), inactive, c, tinted);
|
||||
return (
|
||||
<View
|
||||
key={`${event.id}-${idx}`}
|
||||
style={[
|
||||
styles.chip,
|
||||
{ backgroundColor: colors.fill },
|
||||
colors.bar ? { borderStartWidth: TINTED_BAR_WIDTH, borderStartColor: colors.bar } : null,
|
||||
colors.border !== null && [styles.chipInactive, { borderColor: colors.border }],
|
||||
]}
|
||||
>
|
||||
@@ -327,6 +331,8 @@ function FullWeekRow({
|
||||
}) {
|
||||
const { width } = useWindowDimensions();
|
||||
const { t } = useCalendarLocale();
|
||||
// "Light event colors" (webmail calendarTintedEvents).
|
||||
const tinted = useSettingsStore((s) => s.calendarTintedEvents);
|
||||
const showTime = monthChipShowsTime(showTimeInMonthView, width / 7);
|
||||
return (
|
||||
<View style={[styles.fullWeekRow, { height }]}>
|
||||
@@ -365,7 +371,7 @@ function FullWeekRow({
|
||||
</View>
|
||||
{dayEvents.slice(0, shown).map((event, idx) => {
|
||||
const inactive = isInactiveEvent(event, currentUserEmails);
|
||||
const colors = eventBlockColors(getEventColor(event, calendars), inactive, c);
|
||||
const colors = eventBlockColors(getEventColor(event, calendars), inactive, c, tinted);
|
||||
// No time on events that fill the whole day.
|
||||
const time = showTime && !event.showWithoutTime && !isTimedEventFullDayOnDate(event, d)
|
||||
? `${format(getEventStartDate(event), timePattern(timeFormat), { locale })} `
|
||||
@@ -376,6 +382,7 @@ function FullWeekRow({
|
||||
style={[
|
||||
styles.fullChip,
|
||||
{ backgroundColor: colors.fill },
|
||||
colors.bar ? { borderStartWidth: TINTED_BAR_WIDTH, borderStartColor: colors.bar } : null,
|
||||
colors.border !== null && [styles.chipInactive, { borderColor: colors.border }],
|
||||
]}
|
||||
>
|
||||
|
||||
@@ -19,6 +19,7 @@ import { differenceInCalendarDays, format, type Locale } from 'date-fns';
|
||||
import type { Calendar, CalendarEvent } from '../../api/types';
|
||||
import { spacing, typography, type ThemePalette } from '../../theme/tokens';
|
||||
import { useColors } from '../../theme/colors';
|
||||
import { useSettingsStore } from '../../stores/settings-store';
|
||||
import { useCalendarLocale } from '../../lib/calendar-locale';
|
||||
import { eventAccessibilityLabel } from '../../lib/calendar-a11y';
|
||||
import {
|
||||
@@ -120,6 +121,8 @@ function TimeGridScrollViewInner({
|
||||
onCreateAtTime,
|
||||
}: TimeGridScrollViewProps) {
|
||||
const c = useColors();
|
||||
// "Light event colors" (webmail calendarTintedEvents).
|
||||
const tinted = useSettingsStore((s) => s.calendarTintedEvents);
|
||||
const styles = React.useMemo(() => makeStyles(c), [c]);
|
||||
const { locale, t } = useCalendarLocale();
|
||||
const index = React.useMemo(
|
||||
@@ -448,6 +451,7 @@ function TimeGridScrollViewInner({
|
||||
getEventColor(segment.event, calendars),
|
||||
isInactiveEvent(segment.event, currentUserEmails),
|
||||
c,
|
||||
tinted,
|
||||
)}
|
||||
continuesBefore={segment.continuesBefore}
|
||||
continuesAfter={segment.continuesAfter}
|
||||
@@ -606,6 +610,8 @@ const DayColumn = React.memo(function DayColumn({
|
||||
draftHour: number;
|
||||
}) {
|
||||
const { locale, t } = useCalendarLocale();
|
||||
// "Light event colors" (webmail calendarTintedEvents).
|
||||
const tinted = useSettingsStore((s) => s.calendarTintedEvents);
|
||||
const handleLongPress = React.useCallback(
|
||||
(e: GestureResponderEvent) => {
|
||||
onLongPressAt?.(day, hourAtOffset(e.nativeEvent.locationY, HOUR_HEIGHT));
|
||||
@@ -639,6 +645,7 @@ const DayColumn = React.memo(function DayColumn({
|
||||
getEventColor(event, calendars),
|
||||
isInactiveEvent(event, currentUserEmails),
|
||||
colors,
|
||||
tinted,
|
||||
)}
|
||||
ringColor={colors.background}
|
||||
continuesBefore={continuesBefore}
|
||||
|
||||
@@ -11,6 +11,7 @@ import { displayNow, displayNowMinutes, isDisplayToday } from '../../lib/calenda
|
||||
import type { Calendar, CalendarEvent } from '../../api/types';
|
||||
import { spacing, typography, type ThemePalette } from '../../theme/tokens';
|
||||
import { useColors } from '../../theme/colors';
|
||||
import { useSettingsStore } from '../../stores/settings-store';
|
||||
import { useCalendarLocale } from '../../lib/calendar-locale';
|
||||
import { eventAccessibilityLabel } from '../../lib/calendar-a11y';
|
||||
import {
|
||||
@@ -66,6 +67,8 @@ function WeekViewInner({
|
||||
currentUserEmails,
|
||||
}: WeekViewProps) {
|
||||
const c = useColors();
|
||||
// "Light event colors" (webmail calendarTintedEvents).
|
||||
const tinted = useSettingsStore((s) => s.calendarTintedEvents);
|
||||
const styles = React.useMemo(() => makeStyles(c), [c]);
|
||||
const { locale, t } = useCalendarLocale();
|
||||
const scrollRef = React.useRef<ScrollView>(null);
|
||||
@@ -212,6 +215,7 @@ function WeekViewInner({
|
||||
getEventColor(segment.event, calendars),
|
||||
isInactiveEvent(segment.event, currentUserEmails),
|
||||
c,
|
||||
tinted,
|
||||
)}
|
||||
continuesBefore={segment.continuesBefore}
|
||||
continuesAfter={segment.continuesAfter}
|
||||
@@ -287,6 +291,7 @@ function WeekViewInner({
|
||||
getEventColor(event, calendars),
|
||||
isInactiveEvent(event, currentUserEmails),
|
||||
c,
|
||||
tinted,
|
||||
)}
|
||||
ringColor={c.background}
|
||||
continuesBefore={continuesBefore}
|
||||
|
||||
@@ -44,6 +44,7 @@ export function CalendarSettings() {
|
||||
const timeZone = useSettingsStore((s) => s.calendarTimeZone);
|
||||
const showTimeInMonth = useSettingsStore((s) => s.calendarShowTimeInMonth);
|
||||
const showWeekNumbers = useSettingsStore((s) => s.calendarShowWeekNumbers);
|
||||
const tintedEvents = useSettingsStore((s) => s.calendarTintedEvents);
|
||||
const freeScroll = useSettingsStore((s) => s.calendarFreeScroll);
|
||||
const birthdayCal = useSettingsStore((s) => s.showBirthdayCalendar);
|
||||
const tasksEnabled = useSettingsStore((s) => s.enableCalendarTasks);
|
||||
@@ -135,6 +136,19 @@ export function CalendarSettings() {
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t('calendar.settings.tinted_events', 'Light event colors')}
|
||||
description={t(
|
||||
'calendar.settings.tinted_events_desc',
|
||||
'Show events as a light tint of their calendar color with a colored bar at the start, as in Outlook and on printouts, instead of solid blocks.',
|
||||
)}
|
||||
>
|
||||
<ToggleSwitch
|
||||
checked={tintedEvents}
|
||||
onChange={(v) => update('calendarTintedEvents', v)}
|
||||
/>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t('calendar.settings.show_week_numbers', 'Show week numbers')}
|
||||
description={t('calendar.settings.show_week_numbers_mobile_desc', 'Display week numbers in the month view.')}
|
||||
|
||||
Reference in New Issue
Block a user