Files
upstream-mirror 1d2bfcac0c
Some checks failed
Prosody Plugin Tests / test (push) Failing after 10m11s
Close stale issues and PRs / stale (push) Failing after 1s
snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
2026-09-15 15:56:32 +05:00

99 lines
4.1 KiB
TypeScript

import React, { useEffect, useRef } from 'react';
import { Animated, Text, TextStyle, View, ViewStyle } from 'react-native';
import { useSelector } from 'react-redux';
import { IReduxState } from '../../../app/types';
import { getLocalizedDurationFormatter } from '../../../base/i18n/dateUtil';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import Disk from '../../../time-timer/components/native/Disk';
import { getTimerVisualState, isTimeTimerEnabled } from '../../../time-timer/functions';
import styles, { TIME_TIMER_COLLAPSE_DURATION, TIME_TIMER_DISK } from './styles';
/**
* Native two-segment time-timer pill: scheduled duration | elapsed + a progress
* {@code Disk}. Colours come from the shared {@code getTimerVisualState}. When
* the toolbox hides, it retracts to a disk-only chip.
*
* @returns {ReactElement|null}
*/
const TimeTimerLabel = () => {
const timerState = useSelector((state: IReduxState) => state['features/time-timer']);
const timerEnabled = useSelector(isTimeTimerEnabled);
// Raw `visible` flag, not isToolboxVisible — that selector forces true for
// a solo participant, which would stop the pill collapsing when alone.
const toolboxVisible = useSelector((state: IReduxState) => state['features/toolbox'].visible);
const collapsed = !toolboxVisible;
const opacity = useRef(new Animated.Value(1)).current;
// Fade out then in on collapse/expand so the swap reads as a morph.
useEffect(() => {
opacity.setValue(0);
Animated.timing(opacity, {
duration: TIME_TIMER_COLLAPSE_DURATION / 2,
toValue: 1,
useNativeDriver: true
}).start();
}, [ collapsed, opacity ]);
if (!timerEnabled || !timerState.running) {
return null;
}
const { elapsedSeconds, fillColor, fraction, overrunArcEndDeg, warning } = getTimerVisualState(timerState);
const { expired } = timerState;
const scheduled = getLocalizedDurationFormatter(timerState.durationSeconds * 1000);
const elapsed = getLocalizedDurationFormatter(elapsedSeconds * 1000);
// Expired wins over warning.
let scheduledSegmentBg = BaseTheme.palette.timeTimerNameSegmentBackground;
let timerSegmentBg = BaseTheme.palette.timeTimerTimerSegmentBackground;
let elapsedColor = BaseTheme.palette.timeTimerElapsedText;
if (expired) {
scheduledSegmentBg = BaseTheme.palette.timeTimerExpiredNameSegmentBackground;
timerSegmentBg = BaseTheme.palette.timeTimerExpiredTimerSegmentBackground;
elapsedColor = BaseTheme.palette.timeTimerExpiredText;
} else if (warning) {
scheduledSegmentBg = BaseTheme.palette.timeTimerWarningNameSegmentBackground;
timerSegmentBg = BaseTheme.palette.timeTimerWarningTimerSegmentBackground;
elapsedColor = BaseTheme.palette.timeTimerWarning;
}
const disk = (
<Disk
color = { fillColor }
fraction = { fraction }
overrunArcEndDeg = { overrunArcEndDeg }
size = { TIME_TIMER_DISK } />
);
// Collapsed: just the disk in a fully-rounded chip (web's retracted state).
if (collapsed) {
return (
<Animated.View
style = { [ styles.timeTimerCollapsedChip as ViewStyle, { backgroundColor: timerSegmentBg, opacity } ] }>
{ disk }
</Animated.View>
);
}
return (
<Animated.View style = { [ styles.timeTimerContainer as ViewStyle, { opacity } ] }>
<View style = { [ styles.timeTimerScheduledSegment as ViewStyle, { backgroundColor: scheduledSegmentBg } ] }>
<Text style = { styles.timeTimerScheduledText as TextStyle }>({ scheduled })</Text>
</View>
<View style = { [ styles.timeTimerTimerSegment as ViewStyle, { backgroundColor: timerSegmentBg } ] }>
<Text style = { [ styles.timeTimerElapsedText as TextStyle, { color: elapsedColor } ] }>
{ elapsed }
</Text>
{ disk }
</View>
</Animated.View>
);
};
export default TimeTimerLabel;