import { useRef, useImperativeHandle, forwardRef, useState, useEffect } from 'react' import ConfirmAlert, { type ConfirmAlertType } from '@/components/common/ConfirmAlert' import Text from '@/components/common/Text' import { View } from 'react-native' import Input, { type InputType } from '@/components/common/Input' import { createStyle, toast } from '@/utils/tools' import { useTheme } from '@/store/theme/hook' import { cancelTimeoutExit, getTimeoutExitTime, onTimeUpdate, startTimeoutExit, stopTimeoutExit, useTimeoutExitTimeInfo } from '@/core/player/timeoutExit' import { useI18n } from '@/lang' import CheckBox from './common/CheckBox' import { useSettingValue } from '@/store/setting/hook' import { updateSetting } from '@/core/common' import settingState from '@/store/setting/state' const MAX_MIN = 1440 const rxp = /([1-9]\d*)/ const formatTime = (time: number) => { // let d = parseInt(time / 86400) // d = d ? d.toString() + ':' : '' // time = time % 86400 let h = Math.trunc(time / 3600) let hStr = h ? h.toString() + ':' : '' time = time % 3600 const m = Math.trunc(time / 60).toString().padStart(2, '0') const s = Math.trunc(time % 60).toString().padStart(2, '0') return `${hStr}${m}:${s}` } const Status = () => { const theme = useTheme() const t = useI18n() const exitTimeInfo = useTimeoutExitTimeInfo() return ( { exitTimeInfo.time < 0 ? ( {t('timeout_exit_tip_off')} ) : ( {t('timeout_exit_tip_on', { time: formatTime(exitTimeInfo.time) })} ) } {exitTimeInfo.isPlayedStop ? {t('timeout_exit_btn_wait_tip')} : null} ) } interface TimeInputType { setText: (text: string) => void getText: () => string focus: () => void } const TimeInput = forwardRef((props, ref) => { const theme = useTheme() const [text, setText] = useState('') const inputRef = useRef(null) const t = useI18n() useImperativeHandle(ref, () => ({ getText() { return text.trim() }, setText(text) { setText(text) }, focus() { inputRef.current?.focus() }, })) return ( ) }) const Setting = () => { const t = useI18n() const timeoutExitPlayed = useSettingValue('player.timeoutExitPlayed') const onCheckChange = (check: boolean) => { updateSetting({ 'player.timeoutExitPlayed': check }) } return ( ) } export const useTimeInfo = () => { const [exitTimeInfo, setExitTimeInfo] = useState({ cancelText: '', confirmText: '', isPlayedStop: false, active: false, }) const t = useI18n() useEffect(() => { let active: boolean | null = null const remove = onTimeUpdate((time, isPlayedStop) => { if (time < 0) { if (active) { setExitTimeInfo({ cancelText: isPlayedStop ? t('timeout_exit_btn_wait_cancel') : '', confirmText: '', isPlayedStop, active: false, }) active = false } } else { if (active !== true) { setExitTimeInfo({ cancelText: t('timeout_exit_btn_cancel'), confirmText: t('timeout_exit_btn_update'), isPlayedStop, active: true, }) active = true } } }) return () => { remove() } }, [t]) return exitTimeInfo } export interface TimeoutExitEditModalType { show: () => void } interface TimeoutExitEditModalProps { timeInfo: ReturnType } export default forwardRef(({ timeInfo }, ref) => { const alertRef = useRef(null) const timeInputRef = useRef(null) const [visible, setVisible] = useState(false) const t = useI18n() const handleShow = () => { alertRef.current?.setVisible(true) requestAnimationFrame(() => { if (settingState.setting['player.timeoutExit']) timeInputRef.current?.setText(settingState.setting['player.timeoutExit']) // setTimeout(() => { // timeInputRef.current?.focus() // }, 300) }) } useImperativeHandle(ref, () => ({ show() { if (visible) handleShow() else { setVisible(true) requestAnimationFrame(() => { handleShow() }) } }, })) const handleCancel = () => { if (timeInfo.isPlayedStop) { cancelTimeoutExit() return } if (!timeInfo.active) return stopTimeoutExit() toast(t('timeout_exit_tip_cancel')) } const handleConfirm = () => { let timeStr = timeInputRef.current?.getText() ?? '' if (rxp.test(timeStr)) { // if (timeStr != RegExp.$1) toast(t('input_error')) timeStr = RegExp.$1 if (parseInt(timeStr) > MAX_MIN) { toast(t('timeout_exit_tip_max', { num: MAX_MIN })) // timeStr = timeStr.substring(0, timeStr.length - 1) return } } else { if (timeStr.length) toast(t('input_error')) timeStr = '' } if (!timeStr) return const time = parseInt(timeStr) cancelTimeoutExit() startTimeoutExit(time * 60) toast(t('timeout_exit_tip_on', { time: formatTime(getTimeoutExitTime()) })) updateSetting({ 'player.timeoutExit': String(time) }) alertRef.current?.setVisible(false) } return ( visible ? {t('timeout_exit_min')} : null ) }) const styles = createStyle({ alertContent: { flexShrink: 1, flexDirection: 'column', }, tip: { marginBottom: 8, }, checkbox: { marginTop: 5, }, inputContent: { marginTop: 8, flex: 1, // flexDirection: 'row', alignItems: 'center', }, input: { flexGrow: 1, flexShrink: 1, // borderRadius: 4, // paddingTop: 2, // paddingBottom: 2, }, inputLabel: { marginLeft: 8, }, })