1import { H2 } from '@expo/html-elements';
2import { Pedometer } from 'expo-sensors';
3import * as React from 'react';
4import { ScrollView, Text, View } from 'react-native';
5
6import ListButton from '../components/ListButton';
7import { useResolvedValue } from '../utilities/useResolvedValue';
8
9function usePedometer({ isActive }: { isActive: boolean }): Pedometer.PedometerResult | null {
10  const [data, setData] = React.useState<Pedometer.PedometerResult | null>(null);
11  const listener = React.useRef<Pedometer.PedometerListener | null>(null);
12
13  React.useEffect(() => {
14    return () => {
15      listener.current?.remove();
16    };
17  }, []);
18
19  React.useEffect(() => {
20    if (isActive) {
21      listener.current = Pedometer.watchStepCount(setData);
22    } else {
23      listener.current?.remove();
24    }
25  }, [isActive]);
26
27  return data;
28}
29
30function usePedometerHistory({
31  start,
32  end,
33}: {
34  start: Date;
35  end: Date;
36}): Pedometer.PedometerResult | null {
37  const [data, setData] = React.useState<Pedometer.PedometerResult | null>(null);
38  const isMounted = React.useRef(true);
39
40  React.useEffect(() => {
41    return () => {
42      isMounted.current = false;
43    };
44  }, []);
45
46  React.useEffect(() => {
47    Pedometer.getStepCountAsync(start, end).then(data => {
48      if (isMounted.current) {
49        setData(data);
50      }
51    });
52  }, [start, end]);
53
54  return data;
55}
56
57function StepTrackerView() {
58  const [isActive, setActive] = React.useState(false);
59  const data = usePedometer({ isActive });
60  const message = data?.steps ? `Total steps ${data.steps}` : `Waiting...`;
61  return (
62    <View style={{ padding: 10 }}>
63      <H2>Step Tracker</H2>
64      <ListButton onPress={() => setActive(true)} disabled={isActive} title="Start" />
65      <ListButton onPress={() => setActive(false)} disabled={!isActive} title="Stop" />
66      <Text style={{ paddingTop: 10, fontWeight: 'bold' }}>{message}</Text>
67    </View>
68  );
69}
70
71function StepHistoryMessage() {
72  const today = React.useMemo(() => {
73    return new Date();
74  }, []);
75  const yesterday = React.useMemo(() => {
76    const yesterday = new Date();
77    yesterday.setDate(today.getDate() - 1);
78    return yesterday;
79  }, [today]);
80
81  const data = usePedometerHistory({ start: yesterday, end: today });
82
83  const message = data ? `Steps in the last day: ${data.steps}` : `Loading health data...`;
84  return (
85    <View style={{ padding: 10 }}>
86      <H2>Step History</H2>
87      <Text>{message}</Text>
88    </View>
89  );
90}
91
92export default function PedometerScreen() {
93  const [value] = useResolvedValue(Pedometer.isAvailableAsync);
94
95  if (value === null) {
96    return null;
97  } else if (value === false) {
98    return (
99      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
100        <Text>Pedometer is not available on this platform</Text>
101      </View>
102    );
103  }
104  return (
105    <ScrollView>
106      <StepTrackerView />
107      <StepHistoryMessage />
108    </ScrollView>
109  );
110}
111
112PedometerScreen.navigationOptions = {
113  title: 'Pedometer',
114};
115