Skip to content

Countdown Timer starts counting upward on end #20

@AlanChauchet

Description

@AlanChauchet

Library Version

1.0.0

React Native Version

0.81.5

React Version

19.1.0

Expo Version

54.0.9

Minimal Reproduction

  1. Steps to reproduce

Running this hook when a timer is active :

import { useEffect, useMemo, useRef } from "react";
import { type LiveActivityVariants, Voltra } from "voltra";
import {
  startLiveActivity,
  stopLiveActivity,
  updateLiveActivity,
} from "voltra/client";
import type { IActiveTimer } from "@/types/timer";
import { i18n } from "@/utils/translations";

export function useCurrentTimerLiveActivity(timerEndsAt: number) {
  const timerEndsAtMs = timerEndsAt * 1000;

  const variants = useMemo<LiveActivityVariants>(
    () => ({
      lockScreen: {
        activityBackgroundTint: background,
        content: (
          <Voltra.HStack
            alignment="center"
            spacing={16}
            style={{
              paddingHorizontal: 16,
              paddingVertical: 8,
            }}
          >
            <Voltra.Symbol
              name="bell.fill"
              scale="large"
              tintColor={accent}
              type="hierarchical"
            />
            <Voltra.VStack alignment="leading">
              <Voltra.Text
                numberOfLines={1}
                style={{
                  color: foreground,
                  fontSize: 18,
                  fontWeight: "600" as const,
                }}
              >
                Rest timer
              </Voltra.Text>
            </Voltra.VStack>
            <Voltra.Spacer style={{ flex: 1 }} />
            <Voltra.HStack
              style={{
                width: 80,
              }}
            >
              <Voltra.Spacer style={{ flex: 1 }} />
              <Voltra.Timer
                autoHideOnEnd
                direction="down"
                endAtMs={timerEndsAtMs}
                style={{
                  fontSize: 18,
                  fontWeight: "600",
                  color: muted,
                }}
                textStyle="timer"
              />
            </Voltra.HStack>
          </Voltra.HStack>
        ),
      },
    }),
    [timerEndsAtMs]
  );

  const activityId = useRef<string | null>(null);

  useEffect(() => {
    const start = async () => {
      if (activityId.current) {
        await updateLiveActivity(activityId.current, variants, {
          relevanceScore: 1.0,
          staleDate: timerEndsAtMs,
          dismissalPolicy: "immediate",
        });
      } else {
        const newActivityId = await startLiveActivity(variants, {
          activityName: "current-timer",
          relevanceScore: 1.0,
          staleDate: timerEndsAtMs,
          dismissalPolicy: "immediate",
        });
        activityId.current = newActivityId;
      }
    };

    if (timerEndsAtMs > 0) {
      start();
    } else if (activityId.current) {
      stopLiveActivity(activityId.current);
      activityId.current = null;
    }
  }, [variants, timerEndsAtMs]);

  useEffect(() => {
    return () => {
      if (activityId.current) {
        stopLiveActivity(activityId.current);
        activityId.current = null;
      }
    };
  }, []);
}
  1. Expected behavior

When timerEndsAt is reached, timer is expected to hide (because of autoHideOnEnd) or at least stay at "00:00"

  1. Actual Behavior

Timer goes from "00:30" to "00:00" as expected and then stays displayed and starts counting up

Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-01-16.at.15.41.07.mov

Additional Information (Optional)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions