1.0.1 - Update
- 将时间判断方法改为时间戳判断,修复息屏后无法计时的问题。
This commit is contained in:
Vendored
+45
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"velajs": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"velajs-mcp"
|
||||||
|
],
|
||||||
|
"autoApprove": [
|
||||||
|
"list_devices",
|
||||||
|
"select_devices",
|
||||||
|
"get_debug_status",
|
||||||
|
"start_debug_cli",
|
||||||
|
"start_debug_ide",
|
||||||
|
"stop_debug",
|
||||||
|
"close_all_emulators",
|
||||||
|
"take_screenshot",
|
||||||
|
"list_emulators",
|
||||||
|
"get_snapshot",
|
||||||
|
"get_element",
|
||||||
|
"get_console_logs",
|
||||||
|
"clear_console_logs",
|
||||||
|
"execute_script",
|
||||||
|
"get_network_requests",
|
||||||
|
"clear_network_requests",
|
||||||
|
"tap",
|
||||||
|
"double_tap",
|
||||||
|
"scroll",
|
||||||
|
"swipe",
|
||||||
|
"long_press",
|
||||||
|
"send_key",
|
||||||
|
"input_text",
|
||||||
|
"get_storage",
|
||||||
|
"get_project_info",
|
||||||
|
"build_project",
|
||||||
|
"get_build_settings",
|
||||||
|
"select_build_setting",
|
||||||
|
"get_output_logs",
|
||||||
|
"get_emulator_logs",
|
||||||
|
"get_device_log",
|
||||||
|
"navigate"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"package": "cn.seedsoft.tmtclock",
|
"package": "cn.seedsoft.tmtclock",
|
||||||
"name": "番茄钟",
|
"name": "番茄钟",
|
||||||
"versionName": "1.0.0",
|
"versionName": "1.0.1",
|
||||||
"versionCode": 1,
|
"versionCode": 2,
|
||||||
"minPlatformVersion": 1000,
|
"minPlatformVersion": 1000,
|
||||||
"icon": "/common/logo.png",
|
"icon": "/common/logo.png",
|
||||||
"deviceTypeList": [
|
"deviceTypeList": [
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 息屏期间 setInterval 被挂起,亮屏后立刻补一次时间
|
||||||
|
this.updateTime()
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 息屏期间 setInterval 被挂起,亮屏后立刻补一次时间
|
||||||
|
this.updateTime()
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
|
|||||||
+89
-30
@@ -43,8 +43,13 @@ export default {
|
|||||||
paused: false,
|
paused: false,
|
||||||
isResting: false,
|
isResting: false,
|
||||||
focusDurationSeconds: 1200,
|
focusDurationSeconds: 1200,
|
||||||
focusTotalSeconds: 0,
|
restDurationSeconds: 300,
|
||||||
restTotalSeconds: 0,
|
// 息屏后 setInterval 会被系统挂起,所有计时以时间戳为准
|
||||||
|
phaseEndAt: 0,
|
||||||
|
lastCountedAt: 0,
|
||||||
|
lastPersistAt: 0,
|
||||||
|
focusTotalMs: 0,
|
||||||
|
restTotalMs: 0,
|
||||||
focusTotalText: "00:00:00",
|
focusTotalText: "00:00:00",
|
||||||
restTotalText: "00:00:00"
|
restTotalText: "00:00:00"
|
||||||
},
|
},
|
||||||
@@ -56,51 +61,88 @@ export default {
|
|||||||
this.clockTimer = setInterval(() => this.updateTime(), 1000)
|
this.clockTimer = setInterval(() => this.updateTime(), 1000)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 亮屏后立刻按时间戳补齐息屏期间的进度
|
||||||
|
this.updateTime()
|
||||||
|
this.sync()
|
||||||
|
},
|
||||||
|
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
clearInterval(this.clockTimer)
|
clearInterval(this.clockTimer)
|
||||||
clearInterval(this.countdownTimer)
|
clearInterval(this.countdownTimer)
|
||||||
|
this.countdownTimer = null
|
||||||
|
if (!this.paused) {
|
||||||
|
this.accumulate(Date.now())
|
||||||
|
this.updateStats()
|
||||||
|
}
|
||||||
|
this.persistStats(true)
|
||||||
},
|
},
|
||||||
|
|
||||||
startCountdown(seconds) {
|
startCountdown(seconds) {
|
||||||
clearInterval(this.countdownTimer)
|
|
||||||
this.focusDurationSeconds = seconds > 0 ? seconds : 1200
|
this.focusDurationSeconds = seconds > 0 ? seconds : 1200
|
||||||
this.remaining = this.focusDurationSeconds
|
this.beginPhase(false, this.focusDurationSeconds, Date.now())
|
||||||
this.isResting = false
|
this.ensureTicking()
|
||||||
this.paused = false
|
|
||||||
this.updateCountdown()
|
|
||||||
this.countdownTimer = setInterval(() => this.tick(), 1000)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
startRest() {
|
startRest(startAt) {
|
||||||
this.remaining = 300
|
this.beginPhase(true, this.restDurationSeconds, startAt)
|
||||||
this.isResting = true
|
|
||||||
this.paused = true
|
this.paused = true
|
||||||
|
},
|
||||||
|
|
||||||
|
beginPhase(isResting, durationSeconds, startAt) {
|
||||||
|
this.isResting = isResting
|
||||||
|
this.paused = false
|
||||||
|
this.phaseEndAt = startAt + durationSeconds * 1000
|
||||||
|
this.lastCountedAt = startAt
|
||||||
|
this.remaining = durationSeconds
|
||||||
this.updateCountdown()
|
this.updateCountdown()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ensureTicking() {
|
||||||
|
if (this.countdownTimer === null) {
|
||||||
|
this.countdownTimer = setInterval(() => this.sync(), 1000)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
this.time = `${pad(now.getHours())}:${pad(now.getMinutes())}`
|
this.time = `${pad(now.getHours())}:${pad(now.getMinutes())}`
|
||||||
},
|
},
|
||||||
|
|
||||||
tick() {
|
// 把 lastCountedAt 到 untilAt 之间的时间计入当前阶段的累计值
|
||||||
if (this.paused || this.remaining <= 0) return
|
accumulate(untilAt) {
|
||||||
this.remaining -= 1
|
const delta = untilAt - this.lastCountedAt
|
||||||
if (this.isResting) this.restTotalSeconds += 1
|
if (delta <= 0) return
|
||||||
else this.focusTotalSeconds += 1
|
if (this.isResting) this.restTotalMs += delta
|
||||||
this.updateStats()
|
else this.focusTotalMs += delta
|
||||||
this.persistStats()
|
this.lastCountedAt = untilAt
|
||||||
this.updateCountdown()
|
},
|
||||||
if (this.remaining === 0) {
|
|
||||||
|
sync() {
|
||||||
|
// phaseEndAt 为 0 表示还没开始计时
|
||||||
|
if (this.paused || this.phaseEndAt === 0) return
|
||||||
|
const now = Date.now()
|
||||||
|
// 息屏期间可能已跨过一个或多个阶段,逐段结算
|
||||||
|
while (now >= this.phaseEndAt) {
|
||||||
|
this.accumulate(this.phaseEndAt)
|
||||||
|
const endedAt = this.phaseEndAt
|
||||||
if (this.isResting) {
|
if (this.isResting) {
|
||||||
vibrator.vibrate({ mode: "short" })
|
vibrator.vibrate({ mode: "short" })
|
||||||
this.startCountdown(this.focusDurationSeconds)
|
this.beginPhase(false, this.focusDurationSeconds, endedAt)
|
||||||
} else {
|
} else {
|
||||||
vibrator.vibrate({ mode: "long" })
|
vibrator.vibrate({ mode: "long" })
|
||||||
this.startRest()
|
this.startRest(endedAt)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!this.paused) {
|
||||||
|
this.accumulate(now)
|
||||||
|
this.remaining = Math.max(0, Math.round((this.phaseEndAt - now) / 1000))
|
||||||
|
this.updateCountdown()
|
||||||
|
}
|
||||||
|
this.updateStats()
|
||||||
|
this.persistStats(false)
|
||||||
},
|
},
|
||||||
|
|
||||||
durationSeconds(config) {
|
durationSeconds(config) {
|
||||||
@@ -117,8 +159,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateStats() {
|
updateStats() {
|
||||||
this.focusTotalText = this.formatDuration(this.focusTotalSeconds)
|
this.focusTotalText = this.formatDuration(Math.floor(this.focusTotalMs / 1000))
|
||||||
this.restTotalText = this.formatDuration(this.restTotalSeconds)
|
this.restTotalText = this.formatDuration(Math.floor(this.restTotalMs / 1000))
|
||||||
},
|
},
|
||||||
|
|
||||||
formatDuration(totalSeconds) {
|
formatDuration(totalSeconds) {
|
||||||
@@ -136,8 +178,9 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const stats = JSON.parse(data.text)
|
const stats = JSON.parse(data.text)
|
||||||
if (stats.date === this.today()) {
|
if (stats.date === this.today()) {
|
||||||
this.focusTotalSeconds = parseInt(stats.focus, 10) || 0
|
// 读取是异步的,期间可能已经累计了一点时间,用加法避免被覆盖
|
||||||
this.restTotalSeconds = parseInt(stats.rest, 10) || 0
|
this.focusTotalMs += (parseInt(stats.focus, 10) || 0) * 1000
|
||||||
|
this.restTotalMs += (parseInt(stats.rest, 10) || 0) * 1000
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
this.updateStats()
|
this.updateStats()
|
||||||
@@ -146,13 +189,17 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
persistStats() {
|
persistStats(force) {
|
||||||
|
const now = Date.now()
|
||||||
|
// 每秒写盘没有必要,节流到 5 秒;退出/暂停时强制落盘
|
||||||
|
if (!force && now - this.lastPersistAt < 5000) return
|
||||||
|
this.lastPersistAt = now
|
||||||
file.writeText({
|
file.writeText({
|
||||||
uri: "internal://files/focus-stats.json",
|
uri: "internal://files/focus-stats.json",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
date: this.today(),
|
date: this.today(),
|
||||||
focus: this.focusTotalSeconds,
|
focus: Math.floor(this.focusTotalMs / 1000),
|
||||||
rest: this.restTotalSeconds
|
rest: Math.floor(this.restTotalMs / 1000)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -164,7 +211,19 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
togglePause() {
|
togglePause() {
|
||||||
this.paused = !this.paused
|
if (this.paused) {
|
||||||
|
// 恢复:把剩余秒数换算成新的结束时间戳
|
||||||
|
const now = Date.now()
|
||||||
|
this.phaseEndAt = now + this.remaining * 1000
|
||||||
|
this.lastCountedAt = now
|
||||||
|
this.paused = false
|
||||||
|
this.ensureTicking()
|
||||||
|
} else {
|
||||||
|
this.accumulate(Date.now())
|
||||||
|
this.paused = true
|
||||||
|
this.updateStats()
|
||||||
|
this.persistStats(true)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
stopTimer() {
|
stopTimer() {
|
||||||
|
|||||||
@@ -59,6 +59,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 息屏期间 setInterval 被挂起,亮屏后立刻补一次时间
|
||||||
|
this.updateTime()
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
|
|||||||
@@ -54,8 +54,13 @@ export default {
|
|||||||
paused: false,
|
paused: false,
|
||||||
isResting: false,
|
isResting: false,
|
||||||
focusDurationSeconds: 1200,
|
focusDurationSeconds: 1200,
|
||||||
focusTotalSeconds: 0,
|
restDurationSeconds: 300,
|
||||||
restTotalSeconds: 0,
|
// 息屏后 setInterval 会被系统挂起,所有计时以时间戳为准
|
||||||
|
phaseEndAt: 0,
|
||||||
|
lastCountedAt: 0,
|
||||||
|
lastPersistAt: 0,
|
||||||
|
focusTotalMs: 0,
|
||||||
|
restTotalMs: 0,
|
||||||
focusTotalText: "00:00:00",
|
focusTotalText: "00:00:00",
|
||||||
restTotalText: "00:00:00"
|
restTotalText: "00:00:00"
|
||||||
},
|
},
|
||||||
@@ -72,9 +77,21 @@ export default {
|
|||||||
this.clockTimer = setInterval(() => this.updateTime(), 1000)
|
this.clockTimer = setInterval(() => this.updateTime(), 1000)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 亮屏后立刻按时间戳补齐息屏期间的进度
|
||||||
|
this.updateTime()
|
||||||
|
this.sync()
|
||||||
|
},
|
||||||
|
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
clearInterval(this.clockTimer)
|
clearInterval(this.clockTimer)
|
||||||
clearInterval(this.countdownTimer)
|
clearInterval(this.countdownTimer)
|
||||||
|
this.countdownTimer = null
|
||||||
|
if (!this.paused) {
|
||||||
|
this.accumulate(Date.now())
|
||||||
|
this.updateStats()
|
||||||
|
}
|
||||||
|
this.persistStats(true)
|
||||||
},
|
},
|
||||||
|
|
||||||
loadDuration() {
|
loadDuration() {
|
||||||
@@ -86,54 +103,81 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
startCountdown(seconds) {
|
startCountdown(seconds) {
|
||||||
clearInterval(this.countdownTimer)
|
|
||||||
this.focusDurationSeconds = seconds > 0 ? seconds : 1200
|
this.focusDurationSeconds = seconds > 0 ? seconds : 1200
|
||||||
this.remaining = this.focusDurationSeconds
|
this.beginPhase(false, this.focusDurationSeconds, Date.now())
|
||||||
this.isResting = false
|
this.ensureTicking()
|
||||||
this.paused = false
|
|
||||||
this.updateCountdown()
|
|
||||||
this.countdownTimer = setInterval(() => this.tick(), 1000)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
startRest() {
|
startRest(startAt) {
|
||||||
this.remaining = 5 * 60
|
this.beginPhase(true, this.restDurationSeconds, startAt)
|
||||||
this.isResting = true
|
|
||||||
this.paused = true
|
this.paused = true
|
||||||
|
},
|
||||||
|
|
||||||
|
beginPhase(isResting, durationSeconds, startAt) {
|
||||||
|
this.isResting = isResting
|
||||||
|
this.paused = false
|
||||||
|
this.phaseEndAt = startAt + durationSeconds * 1000
|
||||||
|
this.lastCountedAt = startAt
|
||||||
|
this.remaining = durationSeconds
|
||||||
this.updateCountdown()
|
this.updateCountdown()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ensureTicking() {
|
||||||
|
if (this.countdownTimer === null) {
|
||||||
|
this.countdownTimer = setInterval(() => this.sync(), 1000)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
this.time = `${pad(now.getHours())}:${pad(now.getMinutes())}`
|
this.time = `${pad(now.getHours())}:${pad(now.getMinutes())}`
|
||||||
},
|
},
|
||||||
|
|
||||||
tick() {
|
// 把 lastCountedAt 到 untilAt 之间的时间计入当前阶段的累计值
|
||||||
if (this.paused || this.remaining <= 0) {
|
accumulate(untilAt) {
|
||||||
|
const delta = untilAt - this.lastCountedAt
|
||||||
|
if (delta <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.remaining -= 1
|
|
||||||
if (this.isResting) {
|
if (this.isResting) {
|
||||||
this.restTotalSeconds += 1
|
this.restTotalMs += delta
|
||||||
} else {
|
} else {
|
||||||
this.focusTotalSeconds += 1
|
this.focusTotalMs += delta
|
||||||
}
|
}
|
||||||
this.updateStats()
|
this.lastCountedAt = untilAt
|
||||||
this.persistStats()
|
},
|
||||||
this.updateCountdown()
|
|
||||||
if (this.remaining === 0) {
|
sync() {
|
||||||
|
// phaseEndAt 为 0 表示时长还没读出来,尚未开始计时
|
||||||
|
if (this.paused || this.phaseEndAt === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const now = Date.now()
|
||||||
|
// 息屏期间可能已跨过一个或多个阶段,逐段结算
|
||||||
|
while (now >= this.phaseEndAt) {
|
||||||
|
this.accumulate(this.phaseEndAt)
|
||||||
|
const endedAt = this.phaseEndAt
|
||||||
if (this.isResting) {
|
if (this.isResting) {
|
||||||
vibrator.vibrate({
|
vibrator.vibrate({
|
||||||
mode: "short"
|
mode: "short"
|
||||||
})
|
})
|
||||||
this.startCountdown(this.focusDurationSeconds)
|
this.beginPhase(false, this.focusDurationSeconds, endedAt)
|
||||||
} else {
|
} else {
|
||||||
vibrator.vibrate({
|
vibrator.vibrate({
|
||||||
mode: "long"
|
mode: "long"
|
||||||
})
|
})
|
||||||
this.startRest()
|
this.startRest(endedAt)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!this.paused) {
|
||||||
|
this.accumulate(now)
|
||||||
|
this.remaining = Math.max(0, Math.round((this.phaseEndAt - now) / 1000))
|
||||||
|
this.updateCountdown()
|
||||||
|
}
|
||||||
|
this.updateStats()
|
||||||
|
this.persistStats(false)
|
||||||
},
|
},
|
||||||
|
|
||||||
updateCountdown() {
|
updateCountdown() {
|
||||||
@@ -154,8 +198,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateStats() {
|
updateStats() {
|
||||||
this.focusTotalText = this.formatDuration(this.focusTotalSeconds)
|
this.focusTotalText = this.formatDuration(Math.floor(this.focusTotalMs / 1000))
|
||||||
this.restTotalText = this.formatDuration(this.restTotalSeconds)
|
this.restTotalText = this.formatDuration(Math.floor(this.restTotalMs / 1000))
|
||||||
},
|
},
|
||||||
|
|
||||||
formatDuration(totalSeconds) {
|
formatDuration(totalSeconds) {
|
||||||
@@ -173,8 +217,9 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const stats = JSON.parse(data.text)
|
const stats = JSON.parse(data.text)
|
||||||
if (stats.date === this.today()) {
|
if (stats.date === this.today()) {
|
||||||
this.focusTotalSeconds = parseInt(stats.focus, 10) || 0
|
// 读取是异步的,期间可能已经累计了一点时间,用加法避免被覆盖
|
||||||
this.restTotalSeconds = parseInt(stats.rest, 10) || 0
|
this.focusTotalMs += (parseInt(stats.focus, 10) || 0) * 1000
|
||||||
|
this.restTotalMs += (parseInt(stats.rest, 10) || 0) * 1000
|
||||||
}
|
}
|
||||||
this.updateStats()
|
this.updateStats()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -185,13 +230,19 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
persistStats() {
|
persistStats(force) {
|
||||||
|
const now = Date.now()
|
||||||
|
// 每秒写盘没有必要,节流到 5 秒;退出/切阶段时强制落盘
|
||||||
|
if (!force && now - this.lastPersistAt < 5000) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.lastPersistAt = now
|
||||||
file.writeText({
|
file.writeText({
|
||||||
uri: "internal://files/focus-stats.json",
|
uri: "internal://files/focus-stats.json",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
date: this.today(),
|
date: this.today(),
|
||||||
focus: this.focusTotalSeconds,
|
focus: Math.floor(this.focusTotalMs / 1000),
|
||||||
rest: this.restTotalSeconds
|
rest: Math.floor(this.restTotalMs / 1000)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -203,7 +254,19 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
togglePause() {
|
togglePause() {
|
||||||
this.paused = !this.paused
|
if (this.paused) {
|
||||||
|
// 恢复:把剩余秒数换算成新的结束时间戳
|
||||||
|
const now = Date.now()
|
||||||
|
this.phaseEndAt = now + this.remaining * 1000
|
||||||
|
this.lastCountedAt = now
|
||||||
|
this.paused = false
|
||||||
|
this.ensureTicking()
|
||||||
|
} else {
|
||||||
|
this.accumulate(Date.now())
|
||||||
|
this.paused = true
|
||||||
|
this.updateStats()
|
||||||
|
this.persistStats(true)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
stopTimer() {
|
stopTimer() {
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 息屏期间 setInterval 被挂起,亮屏后立刻补一次时间
|
||||||
|
this.updateTime()
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 息屏期间 setInterval 被挂起,亮屏后立刻补一次时间
|
||||||
|
this.updateTime()
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
|
|||||||
@@ -57,6 +57,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 息屏期间 setInterval 被挂起,亮屏后立刻补一次时间
|
||||||
|
this.updateTime()
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
|
|||||||
+89
-29
@@ -35,7 +35,10 @@ export default {
|
|||||||
private: {
|
private: {
|
||||||
time: "00:00", countdown: "20:00", clockTimer: null, countdownTimer: null,
|
time: "00:00", countdown: "20:00", clockTimer: null, countdownTimer: null,
|
||||||
remaining: 1200, paused: false, isResting: false, focusDurationSeconds: 1200,
|
remaining: 1200, paused: false, isResting: false, focusDurationSeconds: 1200,
|
||||||
focusTotalSeconds: 0, restTotalSeconds: 0,
|
restDurationSeconds: 300,
|
||||||
|
// 息屏后 setInterval 会被系统挂起,所有计时以时间戳为准
|
||||||
|
phaseEndAt: 0, lastCountedAt: 0, lastPersistAt: 0,
|
||||||
|
focusTotalMs: 0, restTotalMs: 0,
|
||||||
focusTotalText: "00:00:00", restTotalText: "00:00:00"
|
focusTotalText: "00:00:00", restTotalText: "00:00:00"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -47,51 +50,88 @@ export default {
|
|||||||
this.clockTimer = setInterval(() => this.updateTime(), 1000)
|
this.clockTimer = setInterval(() => this.updateTime(), 1000)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onShow() {
|
||||||
|
// 亮屏后立刻按时间戳补齐息屏期间的进度
|
||||||
|
this.updateTime()
|
||||||
|
this.sync()
|
||||||
|
},
|
||||||
|
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
clearInterval(this.clockTimer)
|
clearInterval(this.clockTimer)
|
||||||
clearInterval(this.countdownTimer)
|
clearInterval(this.countdownTimer)
|
||||||
|
this.countdownTimer = null
|
||||||
|
if (!this.paused) {
|
||||||
|
this.accumulate(Date.now())
|
||||||
|
this.updateStats()
|
||||||
|
}
|
||||||
|
this.persistStats(true)
|
||||||
},
|
},
|
||||||
|
|
||||||
startCountdown(seconds) {
|
startCountdown(seconds) {
|
||||||
clearInterval(this.countdownTimer)
|
|
||||||
this.focusDurationSeconds = seconds > 0 ? seconds : 1200
|
this.focusDurationSeconds = seconds > 0 ? seconds : 1200
|
||||||
this.remaining = this.focusDurationSeconds
|
this.beginPhase(false, this.focusDurationSeconds, Date.now())
|
||||||
this.isResting = false
|
this.ensureTicking()
|
||||||
this.paused = false
|
|
||||||
this.updateCountdown()
|
|
||||||
this.countdownTimer = setInterval(() => this.tick(), 1000)
|
|
||||||
},
|
},
|
||||||
|
|
||||||
startRest() {
|
startRest(startAt) {
|
||||||
this.remaining = 300
|
this.beginPhase(true, this.restDurationSeconds, startAt)
|
||||||
this.isResting = true
|
|
||||||
this.paused = true
|
this.paused = true
|
||||||
|
},
|
||||||
|
|
||||||
|
beginPhase(isResting, durationSeconds, startAt) {
|
||||||
|
this.isResting = isResting
|
||||||
|
this.paused = false
|
||||||
|
this.phaseEndAt = startAt + durationSeconds * 1000
|
||||||
|
this.lastCountedAt = startAt
|
||||||
|
this.remaining = durationSeconds
|
||||||
this.updateCountdown()
|
this.updateCountdown()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ensureTicking() {
|
||||||
|
if (this.countdownTimer === null) {
|
||||||
|
this.countdownTimer = setInterval(() => this.sync(), 1000)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
updateTime() {
|
updateTime() {
|
||||||
const now = new Date()
|
const now = new Date()
|
||||||
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
const pad = (value) => (value < 10 ? `0${value}` : `${value}`)
|
||||||
this.time = `${pad(now.getHours())}:${pad(now.getMinutes())}`
|
this.time = `${pad(now.getHours())}:${pad(now.getMinutes())}`
|
||||||
},
|
},
|
||||||
|
|
||||||
tick() {
|
// 把 lastCountedAt 到 untilAt 之间的时间计入当前阶段的累计值
|
||||||
if (this.paused || this.remaining <= 0) return
|
accumulate(untilAt) {
|
||||||
this.remaining -= 1
|
const delta = untilAt - this.lastCountedAt
|
||||||
if (this.isResting) this.restTotalSeconds += 1
|
if (delta <= 0) return
|
||||||
else this.focusTotalSeconds += 1
|
if (this.isResting) this.restTotalMs += delta
|
||||||
this.updateStats()
|
else this.focusTotalMs += delta
|
||||||
this.persistStats()
|
this.lastCountedAt = untilAt
|
||||||
this.updateCountdown()
|
},
|
||||||
if (this.remaining === 0) {
|
|
||||||
|
sync() {
|
||||||
|
// phaseEndAt 为 0 表示还没开始计时
|
||||||
|
if (this.paused || this.phaseEndAt === 0) return
|
||||||
|
const now = Date.now()
|
||||||
|
// 息屏期间可能已跨过一个或多个阶段,逐段结算
|
||||||
|
while (now >= this.phaseEndAt) {
|
||||||
|
this.accumulate(this.phaseEndAt)
|
||||||
|
const endedAt = this.phaseEndAt
|
||||||
if (this.isResting) {
|
if (this.isResting) {
|
||||||
vibrator.vibrate({ mode: "short" })
|
vibrator.vibrate({ mode: "short" })
|
||||||
this.startCountdown(this.focusDurationSeconds)
|
this.beginPhase(false, this.focusDurationSeconds, endedAt)
|
||||||
} else {
|
} else {
|
||||||
vibrator.vibrate({ mode: "long" })
|
vibrator.vibrate({ mode: "long" })
|
||||||
this.startRest()
|
this.startRest(endedAt)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!this.paused) {
|
||||||
|
this.accumulate(now)
|
||||||
|
this.remaining = Math.max(0, Math.round((this.phaseEndAt - now) / 1000))
|
||||||
|
this.updateCountdown()
|
||||||
|
}
|
||||||
|
this.updateStats()
|
||||||
|
this.persistStats(false)
|
||||||
},
|
},
|
||||||
|
|
||||||
durationSeconds(config) {
|
durationSeconds(config) {
|
||||||
@@ -108,8 +148,8 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
updateStats() {
|
updateStats() {
|
||||||
this.focusTotalText = this.formatDuration(this.focusTotalSeconds)
|
this.focusTotalText = this.formatDuration(Math.floor(this.focusTotalMs / 1000))
|
||||||
this.restTotalText = this.formatDuration(this.restTotalSeconds)
|
this.restTotalText = this.formatDuration(Math.floor(this.restTotalMs / 1000))
|
||||||
},
|
},
|
||||||
|
|
||||||
formatDuration(totalSeconds) {
|
formatDuration(totalSeconds) {
|
||||||
@@ -127,8 +167,9 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const stats = JSON.parse(data.text)
|
const stats = JSON.parse(data.text)
|
||||||
if (stats.date === this.today()) {
|
if (stats.date === this.today()) {
|
||||||
this.focusTotalSeconds = parseInt(stats.focus, 10) || 0
|
// 读取是异步的,期间可能已经累计了一点时间,用加法避免被覆盖
|
||||||
this.restTotalSeconds = parseInt(stats.rest, 10) || 0
|
this.focusTotalMs += (parseInt(stats.focus, 10) || 0) * 1000
|
||||||
|
this.restTotalMs += (parseInt(stats.rest, 10) || 0) * 1000
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
this.updateStats()
|
this.updateStats()
|
||||||
@@ -137,13 +178,17 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
persistStats() {
|
persistStats(force) {
|
||||||
|
const now = Date.now()
|
||||||
|
// 每秒写盘没有必要,节流到 5 秒;退出/暂停时强制落盘
|
||||||
|
if (!force && now - this.lastPersistAt < 5000) return
|
||||||
|
this.lastPersistAt = now
|
||||||
file.writeText({
|
file.writeText({
|
||||||
uri: "internal://files/focus-stats.json",
|
uri: "internal://files/focus-stats.json",
|
||||||
text: JSON.stringify({
|
text: JSON.stringify({
|
||||||
date: this.today(),
|
date: this.today(),
|
||||||
focus: this.focusTotalSeconds,
|
focus: Math.floor(this.focusTotalMs / 1000),
|
||||||
rest: this.restTotalSeconds
|
rest: Math.floor(this.restTotalMs / 1000)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@@ -154,7 +199,22 @@ export default {
|
|||||||
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`
|
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`
|
||||||
},
|
},
|
||||||
|
|
||||||
togglePause() { this.paused = !this.paused },
|
togglePause() {
|
||||||
|
if (this.paused) {
|
||||||
|
// 恢复:把剩余秒数换算成新的结束时间戳
|
||||||
|
const now = Date.now()
|
||||||
|
this.phaseEndAt = now + this.remaining * 1000
|
||||||
|
this.lastCountedAt = now
|
||||||
|
this.paused = false
|
||||||
|
this.ensureTicking()
|
||||||
|
} else {
|
||||||
|
this.accumulate(Date.now())
|
||||||
|
this.paused = true
|
||||||
|
this.updateStats()
|
||||||
|
this.persistStats(true)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
stopTimer() { router.back() }
|
stopTimer() { router.back() }
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user