@@ -10,13 +10,17 @@ interface ADHDState {
1010 isVisible : boolean ;
1111 duration : number ;
1212 remainingTime : number ;
13+ isExploding : boolean ;
1314}
1415
1516type ADHDAction =
1617 | { type : "SHOW" ; payload : { duration : number } }
1718 | { type : "HIDE" }
1819 | { type : "TICK" }
19- | { type : "EXTEND" ; payload : { duration : number } } ;
20+ | { type : "EXTEND" ; payload : { duration : number } }
21+ | { type : "START_EXPLOSION" }
22+ | { type : "FINISH_EXPLOSION" }
23+ | { type : "COMPLETE_EXPLOSION" } ;
2024
2125const adhdReducer = ( state : ADHDState , action : ADHDAction ) : ADHDState => {
2226 switch ( action . type ) {
@@ -25,31 +29,55 @@ const adhdReducer = (state: ADHDState, action: ADHDAction): ADHDState => {
2529 isVisible : true ,
2630 duration : action . payload . duration ,
2731 remainingTime : action . payload . duration ,
32+ isExploding : false ,
2833 } ;
2934 case "HIDE" :
3035 return {
3136 ...state ,
3237 isVisible : false ,
3338 remainingTime : 0 ,
39+ isExploding : false ,
3440 } ;
3541 case "TICK" :
3642 if ( state . remainingTime <= 1 ) {
3743 return {
3844 ...state ,
39- isVisible : false ,
40- remainingTime : 0 ,
45+ isExploding : true ,
4146 } ;
4247 }
4348 return {
4449 ...state ,
4550 remainingTime : state . remainingTime - 1 ,
4651 } ;
4752 case "EXTEND" :
53+ if ( state . isExploding ) {
54+ // Если идет взрыв, добавляем в очередь
55+ return state ;
56+ }
4857 return {
4958 ...state ,
5059 duration : state . duration + action . payload . duration ,
5160 remainingTime : state . remainingTime + action . payload . duration ,
5261 } ;
62+ case "START_EXPLOSION" :
63+ return {
64+ ...state ,
65+ isExploding : true ,
66+ } ;
67+ case "FINISH_EXPLOSION" :
68+ return {
69+ ...state ,
70+ isVisible : false ,
71+ remainingTime : 0 ,
72+ // isExploding остается true для продолжения воспроизведения видео
73+ } ;
74+ case "COMPLETE_EXPLOSION" :
75+ return {
76+ ...state ,
77+ isVisible : false ,
78+ remainingTime : 0 ,
79+ isExploding : false ,
80+ } ;
5381 default :
5482 return state ;
5583 }
@@ -59,12 +87,15 @@ const initialState: ADHDState = {
5987 isVisible : false ,
6088 duration : 0 ,
6189 remainingTime : 0 ,
90+ isExploding : false ,
6291} ;
6392
6493export function ADHDController ( ) {
6594 const [ announced , setAnnounced ] = useState < boolean > ( false ) ;
6695 const [ state , dispatch ] = useReducer ( adhdReducer , initialState ) ;
96+ const [ pendingExtensions , setPendingExtensions ] = useState < number [ ] > ( [ ] ) ;
6797 const intervalRef = useRef < NodeJS . Timeout | null > ( null ) ;
98+ const explosionRef = useRef < HTMLVideoElement | null > ( null ) ;
6899
69100 // Функция форматирования времени в формат MM:SS
70101 const formatTime = ( seconds : number ) : string => {
@@ -74,6 +105,12 @@ export function ADHDController() {
74105 } ;
75106
76107 const handleMessage = ( duration : number ) => {
108+ if ( state . isExploding ) {
109+ // Если идет взрыв, добавляем в очередь продлений
110+ setPendingExtensions ( prev => [ ...prev , duration ] ) ;
111+ return ;
112+ }
113+
77114 if ( state . isVisible ) {
78115 // Если уже показывается, продлеваем время
79116 dispatch ( { type : "EXTEND" , payload : { duration } } ) ;
@@ -87,10 +124,11 @@ export function ADHDController() {
87124 SignalRContext . useSignalREffect ( "adhd" , handleMessage , [
88125 handleMessage ,
89126 state . isVisible ,
127+ state . isExploding ,
90128 ] ) ;
91129
92130 useEffect ( ( ) => {
93- if ( state . isVisible && state . remainingTime > 0 ) {
131+ if ( state . isVisible && state . remainingTime > 0 && ! state . isExploding ) {
94132 intervalRef . current = setInterval ( ( ) => {
95133 dispatch ( { type : "TICK" } ) ;
96134 } , 1000 ) ;
@@ -107,7 +145,41 @@ export function ADHDController() {
107145 intervalRef . current = null ;
108146 }
109147 } ;
110- } , [ state . isVisible , state . remainingTime ] ) ;
148+ } , [ state . isVisible , state . remainingTime , state . isExploding ] ) ;
149+
150+ useEffect ( ( ) => {
151+ if ( state . isExploding && explosionRef . current ) {
152+ const videoElement = explosionRef . current ;
153+ videoElement . play ( ) ;
154+
155+ // Скрываем ADHDPage через 2 секунды после начала взрыва
156+ const hideTimer = setTimeout ( ( ) => {
157+ dispatch ( { type : "FINISH_EXPLOSION" } ) ;
158+
159+ // Проверяем очередь продлений
160+ if ( pendingExtensions . length > 0 ) {
161+ const totalExtension = pendingExtensions . reduce (
162+ ( sum , ext ) => sum + ext ,
163+ 0
164+ ) ;
165+ setPendingExtensions ( [ ] ) ;
166+ dispatch ( { type : "SHOW" , payload : { duration : totalExtension } } ) ;
167+ }
168+ } , 2000 ) ;
169+
170+ // Ждем окончания видео для полного завершения состояния
171+ const handleVideoEnd = ( ) => {
172+ dispatch ( { type : "COMPLETE_EXPLOSION" } ) ;
173+ } ;
174+
175+ videoElement . addEventListener ( "ended" , handleVideoEnd ) ;
176+
177+ return ( ) => {
178+ clearTimeout ( hideTimer ) ;
179+ videoElement . removeEventListener ( "ended" , handleVideoEnd ) ;
180+ } ;
181+ }
182+ } , [ state . isExploding , pendingExtensions ] ) ;
111183
112184 return (
113185 < >
@@ -126,6 +198,15 @@ export function ADHDController() {
126198 </ div >
127199 </ div >
128200 ) }
201+ { state . isExploding && (
202+ < video
203+ ref = { explosionRef }
204+ className = { styles . explosionVideo }
205+ src = "/src/components/OBS_Components/ADHDLayout/content/explosion.webm"
206+ autoPlay
207+ muted
208+ />
209+ ) }
129210 </ >
130211 ) ;
131212}
0 commit comments