280 lines
7.5 KiB
JavaScript
280 lines
7.5 KiB
JavaScript
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
|
import { BackHandler, Platform, StatusBar } from 'react-native';
|
|
import * as ScreenOrientation from 'expo-screen-orientation';
|
|
import FocusScreen from './src/screens/FocusScreen';
|
|
import HomeScreen from './src/screens/HomeScreen';
|
|
import TimeUntilScreen from './src/screens/TimeUntilScreen';
|
|
import TimerScreen from './src/screens/TimerScreen';
|
|
import { createStyles } from './src/styles';
|
|
import { getTheme } from './src/theme';
|
|
|
|
export default function App() {
|
|
const styles = useMemo(() => createStyles(), []);
|
|
|
|
const [screen, setScreen] = useState('home');
|
|
const [focusMode, setFocusMode] = useState(false);
|
|
const [darkMode, setDarkMode] = useState(true);
|
|
const [pinkMode, setPinkMode] = useState(false);
|
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
const [now, setNow] = useState(new Date());
|
|
|
|
const [targetTime, setTargetTime] = useState(null);
|
|
const [tuHour, setTuHour] = useState('');
|
|
const [tuMinute, setTuMinute] = useState('');
|
|
const [tuIsOver, setTuIsOver] = useState(false);
|
|
|
|
const [timerRunning, setTimerRunning] = useState(false);
|
|
const [timerDone, setTimerDone] = useState(false);
|
|
const [timerRemaining, setTimerRemaining] = useState(0);
|
|
const [timerHInput, setTimerHInput] = useState('');
|
|
const [timerMInput, setTimerMInput] = useState('');
|
|
const [timerSInput, setTimerSInput] = useState('');
|
|
|
|
const timerRef = useRef(null);
|
|
const theme = getTheme(darkMode, pinkMode);
|
|
|
|
useEffect(() => {
|
|
if (Platform.OS !== 'web') {
|
|
ScreenOrientation.unlockAsync();
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const interval = setInterval(() => setNow(new Date()), 1000);
|
|
return () => clearInterval(interval);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (targetTime && now >= targetTime) {
|
|
setTuIsOver(true);
|
|
} else {
|
|
setTuIsOver(false);
|
|
}
|
|
}, [now, targetTime]);
|
|
|
|
useEffect(() => {
|
|
if (timerRunning) {
|
|
timerRef.current = setInterval(() => {
|
|
setTimerRemaining((r) => {
|
|
if (r <= 1) {
|
|
clearInterval(timerRef.current);
|
|
setTimerRunning(false);
|
|
setTimerDone(true);
|
|
return 0;
|
|
}
|
|
return r - 1;
|
|
});
|
|
}, 1000);
|
|
}
|
|
|
|
return () => clearInterval(timerRef.current);
|
|
}, [timerRunning]);
|
|
|
|
useEffect(() => {
|
|
if (Platform.OS !== 'android') return undefined;
|
|
|
|
const sub = BackHandler.addEventListener('hardwareBackPress', () => {
|
|
if (focusMode) {
|
|
setFocusMode(false);
|
|
return true;
|
|
}
|
|
|
|
if (screen !== 'home') {
|
|
setScreen('home');
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
return () => sub.remove();
|
|
}, [focusMode, screen]);
|
|
|
|
const toggleFullscreen = () => {
|
|
if (Platform.OS !== 'web') return;
|
|
|
|
if (!document.fullscreenElement) {
|
|
document.documentElement.requestFullscreen();
|
|
setIsFullscreen(true);
|
|
} else {
|
|
document.exitFullscreen();
|
|
setIsFullscreen(false);
|
|
}
|
|
};
|
|
|
|
const setTuTimer = () => {
|
|
const h = parseInt(tuHour, 10);
|
|
const m = parseInt(tuMinute, 10);
|
|
|
|
if (isNaN(h) || isNaN(m) || h < 0 || h > 23 || m < 0 || m > 59) return;
|
|
|
|
const target = new Date();
|
|
target.setHours(h, m, 0, 0);
|
|
if (target <= new Date()) {
|
|
target.setDate(target.getDate() + 1);
|
|
}
|
|
|
|
setTargetTime(target);
|
|
setTuIsOver(false);
|
|
};
|
|
|
|
const resetTuTimer = () => {
|
|
setTargetTime(null);
|
|
setTuIsOver(false);
|
|
setTuHour('');
|
|
setTuMinute('');
|
|
};
|
|
|
|
const getTuCountdown = () => {
|
|
if (!targetTime) return null;
|
|
const diff = targetTime - now;
|
|
if (diff <= 0) return null;
|
|
|
|
const t = Math.floor(diff / 1000);
|
|
return {
|
|
hours: Math.floor(t / 3600),
|
|
minutes: Math.floor((t % 3600) / 60),
|
|
seconds: t % 60,
|
|
};
|
|
};
|
|
|
|
const startTimer = () => {
|
|
const h = parseInt(timerHInput, 10) || 0;
|
|
const m = parseInt(timerMInput, 10) || 0;
|
|
const s = parseInt(timerSInput, 10) || 0;
|
|
const total = h * 3600 + m * 60 + s;
|
|
|
|
if (total <= 0) return;
|
|
|
|
setTimerRemaining(total);
|
|
setTimerDone(false);
|
|
setTimerRunning(true);
|
|
};
|
|
|
|
const resetTimerState = () => {
|
|
clearInterval(timerRef.current);
|
|
setTimerRunning(false);
|
|
setTimerDone(false);
|
|
setTimerRemaining(0);
|
|
setTimerHInput('');
|
|
setTimerMInput('');
|
|
setTimerSInput('');
|
|
};
|
|
|
|
const timerHr = Math.floor(timerRemaining / 3600);
|
|
const timerMin = Math.floor((timerRemaining % 3600) / 60);
|
|
const timerSec = timerRemaining % 60;
|
|
const tuCountdown = getTuCountdown();
|
|
|
|
if (focusMode) {
|
|
return (
|
|
<FocusScreen
|
|
styles={styles}
|
|
theme={theme}
|
|
screen={screen}
|
|
pinkMode={pinkMode}
|
|
tuIsOver={tuIsOver}
|
|
tuCountdown={tuCountdown}
|
|
targetTime={targetTime}
|
|
timerDone={timerDone}
|
|
timerHr={timerHr}
|
|
timerMin={timerMin}
|
|
timerSec={timerSec}
|
|
onShowUI={() => setFocusMode(false)}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const barStyle = darkMode ? 'light-content' : 'dark-content';
|
|
|
|
if (screen === 'home') {
|
|
return (
|
|
<>
|
|
<StatusBar barStyle={barStyle} backgroundColor={theme.bg} />
|
|
<HomeScreen
|
|
styles={styles}
|
|
theme={theme}
|
|
now={now}
|
|
darkMode={darkMode}
|
|
pinkMode={pinkMode}
|
|
isFullscreen={isFullscreen}
|
|
onToggleDark={() => setDarkMode((d) => !d)}
|
|
onTogglePink={() => setPinkMode((p) => !p)}
|
|
onToggleFullscreen={toggleFullscreen}
|
|
onSelectTimeUntil={() => setScreen('timeuntil')}
|
|
onSelectTimer={() => setScreen('timer')}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
|
|
if (screen === 'timeuntil') {
|
|
return (
|
|
<>
|
|
<StatusBar barStyle={barStyle} backgroundColor={theme.bg} />
|
|
<TimeUntilScreen
|
|
styles={styles}
|
|
theme={theme}
|
|
now={now}
|
|
darkMode={darkMode}
|
|
pinkMode={pinkMode}
|
|
isFullscreen={isFullscreen}
|
|
targetTime={targetTime}
|
|
tuHour={tuHour}
|
|
tuMinute={tuMinute}
|
|
tuIsOver={tuIsOver}
|
|
tuCountdown={tuCountdown}
|
|
onChangeHour={setTuHour}
|
|
onChangeMinute={setTuMinute}
|
|
onSetTimer={setTuTimer}
|
|
onResetTimer={resetTuTimer}
|
|
onBackToMenu={() => setScreen('home')}
|
|
onToggleDark={() => setDarkMode((d) => !d)}
|
|
onTogglePink={() => setPinkMode((p) => !p)}
|
|
onToggleFullscreen={toggleFullscreen}
|
|
onFocus={() => setFocusMode(true)}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<StatusBar barStyle={barStyle} backgroundColor={theme.bg} />
|
|
<TimerScreen
|
|
styles={styles}
|
|
theme={theme}
|
|
now={now}
|
|
darkMode={darkMode}
|
|
pinkMode={pinkMode}
|
|
isFullscreen={isFullscreen}
|
|
timerRunning={timerRunning}
|
|
timerDone={timerDone}
|
|
timerRemaining={timerRemaining}
|
|
timerHInput={timerHInput}
|
|
timerMInput={timerMInput}
|
|
timerSInput={timerSInput}
|
|
timerHr={timerHr}
|
|
timerMin={timerMin}
|
|
timerSec={timerSec}
|
|
onChangeH={setTimerHInput}
|
|
onChangeM={setTimerMInput}
|
|
onChangeS={setTimerSInput}
|
|
onStart={startTimer}
|
|
onPause={() => setTimerRunning(false)}
|
|
onResume={() => {
|
|
if (timerRemaining > 0) {
|
|
setTimerRunning(true);
|
|
}
|
|
}}
|
|
onReset={resetTimerState}
|
|
onBackToMenu={() => setScreen('home')}
|
|
onToggleDark={() => setDarkMode((d) => !d)}
|
|
onTogglePink={() => setPinkMode((p) => !p)}
|
|
onToggleFullscreen={toggleFullscreen}
|
|
onFocus={() => setFocusMode(true)}
|
|
/>
|
|
</>
|
|
);
|
|
}
|