Tie break timer and main block timer together
- Starting break now pauses the main block timer (frontend optimistic + backend implicit pause event recorded before break_start) - Resuming/starting the main block while break is active pauses the break timer and exits break mode on all clients including TV - Timer display counts negative past zero so overtime is visible while label stays "Done!" - Fixed WS start handler incorrectly skipping break-mode clear when restarting the same block; resume handler now also clears break mode Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -58,10 +58,12 @@ const elapsed = computed(() => {
|
||||
const remaining = computed(() => Math.max(0, blockDuration.value - elapsed.value))
|
||||
|
||||
const display = computed(() => {
|
||||
const s = remaining.value
|
||||
const m = Math.floor(s / 60)
|
||||
const sec = s % 60
|
||||
return `${String(m).padStart(2, '0')}:${String(sec).padStart(2, '0')}`
|
||||
const s = blockDuration.value - elapsed.value
|
||||
if (s < 0) {
|
||||
const abs = Math.abs(s)
|
||||
return `-${String(Math.floor(abs / 60)).padStart(2, '0')}:${String(abs % 60).padStart(2, '0')}`
|
||||
}
|
||||
return `${String(Math.floor(s / 60)).padStart(2, '0')}:${String(s % 60).padStart(2, '0')}`
|
||||
})
|
||||
|
||||
const label = computed(() => {
|
||||
@@ -72,7 +74,7 @@ const label = computed(() => {
|
||||
const CIRCUMFERENCE = 2 * Math.PI * 88
|
||||
const dashOffset = computed(() => {
|
||||
if (!blockDuration.value) return CIRCUMFERENCE
|
||||
const pct = remaining.value / blockDuration.value
|
||||
const pct = Math.max(0, remaining.value / blockDuration.value)
|
||||
return CIRCUMFERENCE * (1 - pct)
|
||||
})
|
||||
|
||||
|
||||
@@ -95,6 +95,12 @@ export const useScheduleStore = defineStore('schedule', () => {
|
||||
if (event.block_id) breakElapsedCache.value[event.block_id] = elapsed
|
||||
breakStartedAt.value = Date.now()
|
||||
isBreakMode.value = true
|
||||
// Sync main block timer to server-authoritative elapsed and mark paused
|
||||
const blockElapsed = event.block_elapsed_seconds ?? blockElapsedCache.value[event.block_id] ?? blockElapsedOffset.value
|
||||
blockElapsedOffset.value = blockElapsed
|
||||
if (event.block_id) blockElapsedCache.value[event.block_id] = blockElapsed
|
||||
blockStartedAt.value = null
|
||||
isPaused.value = true
|
||||
}
|
||||
if (event.event === 'break_pause') {
|
||||
if (breakStartedAt.value) {
|
||||
@@ -140,12 +146,9 @@ export const useScheduleStore = defineStore('schedule', () => {
|
||||
}
|
||||
blockStartedAt.value = Date.now()
|
||||
isPaused.value = false
|
||||
// Switching to a new block clears break mode
|
||||
if (event.block_id !== event.current_block_id || !isBreakMode.value) {
|
||||
isBreakMode.value = false
|
||||
breakStartedAt.value = null
|
||||
breakElapsedOffset.value = breakElapsedCache.value[event.block_id] ?? 0
|
||||
}
|
||||
isBreakMode.value = false
|
||||
breakStartedAt.value = null
|
||||
breakElapsedOffset.value = breakElapsedCache.value[event.block_id] ?? 0
|
||||
}
|
||||
// Reset — clear elapsed to 0 and start counting immediately
|
||||
if (event.event === 'reset') {
|
||||
@@ -175,6 +178,8 @@ export const useScheduleStore = defineStore('schedule', () => {
|
||||
if (event.event === 'resume') {
|
||||
blockStartedAt.value = Date.now()
|
||||
isPaused.value = false
|
||||
isBreakMode.value = false
|
||||
breakStartedAt.value = null
|
||||
}
|
||||
// Timer events update session state
|
||||
if (event.current_block_id !== undefined && session.value) {
|
||||
@@ -256,15 +261,51 @@ export const useScheduleStore = defineStore('schedule', () => {
|
||||
// Start the timer for the currently selected block (optimistic).
|
||||
function startCurrentBlock(sessionId) {
|
||||
if (!session.value?.current_block_id) return
|
||||
const blockId = session.value.current_block_id
|
||||
if (isBreakMode.value) {
|
||||
if (breakStartedAt.value) {
|
||||
breakElapsedOffset.value += Math.floor((Date.now() - breakStartedAt.value) / 1000)
|
||||
}
|
||||
breakElapsedCache.value[blockId] = breakElapsedOffset.value
|
||||
breakStartedAt.value = null
|
||||
isBreakMode.value = false
|
||||
sendTimerAction(sessionId, 'break_pause', blockId)
|
||||
}
|
||||
isPaused.value = false
|
||||
blockStartedAt.value = Date.now()
|
||||
sendTimerAction(sessionId, 'start', session.value.current_block_id)
|
||||
sendTimerAction(sessionId, 'start', blockId)
|
||||
}
|
||||
|
||||
// Resume the timer for the currently selected block (optimistic).
|
||||
function resumeCurrentBlock(sessionId) {
|
||||
if (!session.value?.current_block_id) return
|
||||
const blockId = session.value.current_block_id
|
||||
if (isBreakMode.value) {
|
||||
if (breakStartedAt.value) {
|
||||
breakElapsedOffset.value += Math.floor((Date.now() - breakStartedAt.value) / 1000)
|
||||
}
|
||||
breakElapsedCache.value[blockId] = breakElapsedOffset.value
|
||||
breakStartedAt.value = null
|
||||
isBreakMode.value = false
|
||||
sendTimerAction(sessionId, 'break_pause', blockId)
|
||||
}
|
||||
blockStartedAt.value = Date.now()
|
||||
isPaused.value = false
|
||||
sendTimerAction(sessionId, 'resume')
|
||||
}
|
||||
|
||||
// Break timer actions
|
||||
function startBreak(sessionId) {
|
||||
if (!session.value?.current_block_id) return
|
||||
const blockId = session.value.current_block_id
|
||||
// Pause the main block timer
|
||||
if (blockStartedAt.value) {
|
||||
blockElapsedOffset.value += Math.floor((Date.now() - blockStartedAt.value) / 1000)
|
||||
}
|
||||
blockElapsedCache.value[blockId] = blockElapsedOffset.value
|
||||
blockStartedAt.value = null
|
||||
isPaused.value = true
|
||||
// Start break timer
|
||||
isBreakMode.value = true
|
||||
breakElapsedOffset.value = breakElapsedCache.value[blockId] ?? 0
|
||||
breakStartedAt.value = Date.now()
|
||||
@@ -332,6 +373,7 @@ export const useScheduleStore = defineStore('schedule', () => {
|
||||
switchBlock,
|
||||
selectBlock,
|
||||
startCurrentBlock,
|
||||
resumeCurrentBlock,
|
||||
resetCurrentBlock,
|
||||
startBreak,
|
||||
pauseBreak,
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<button
|
||||
class="btn-sm"
|
||||
v-if="scheduleStore.isPaused && scheduleStore.blockElapsedOffset > 0"
|
||||
@click="sendAction('resume')"
|
||||
@click="scheduleStore.resumeCurrentBlock(scheduleStore.session.id)"
|
||||
>Resume</button>
|
||||
<button
|
||||
class="btn-sm"
|
||||
|
||||
Reference in New Issue
Block a user