diff --git a/config.js b/config.js index 3d6542e..1bf5ad2 100644 --- a/config.js +++ b/config.js @@ -24,7 +24,7 @@ module.exports = { * speed: 语速 -2~2(正数加快,0 为默认)。 */ tts: { - female: { voiceType: 502005, volume: 9, speed: 1 }, - male: { voiceType: 602005, volume: 9, speed: 1 } + female: { voiceType: 501004, volume: 9, speed: 1 }, + male: { voiceType: 502005, volume: 9, speed: 1 } } } diff --git a/pages/settings/settings.js b/pages/settings/settings.js index 586fa6d..af58fcc 100644 --- a/pages/settings/settings.js +++ b/pages/settings/settings.js @@ -58,6 +58,12 @@ Page({ { key: 'female', name: '女声' }, { key: 'male', name: '男声' } ], + vibrateIntensity: 'heavy', + vibrateIntensityOptions: [ + { key: 'light', name: '短促' }, + { key: 'medium', name: '标准' }, + { key: 'heavy', name: '强烈' } + ], icons: iconsMod.build(), nickName: '', avatarUrl: '', @@ -92,6 +98,7 @@ Page({ voiceGuide: s.voiceGuide, vibrate: s.vibrate, voiceGender: s.voiceGender || 'female', + vibrateIntensity: s.vibrateIntensity || 'heavy', currentThemeId: theme.id, theme, icons: iconsMod.build(theme), @@ -253,6 +260,15 @@ Page({ this.setData({ voiceGender: key }) }, + onSelectVibrateIntensity(e) { + const key = e.currentTarget.dataset.key + if (key === this.data.vibrateIntensity) return + const s = storage.getSettings() + s.vibrateIntensity = key + storage.saveSettings(s) + this.setData({ vibrateIntensity: key }) + }, + onCopyWechat() { wx.setClipboardData({ data: config.developer, diff --git a/pages/settings/settings.wxml b/pages/settings/settings.wxml index 98a872d..df12838 100644 --- a/pages/settings/settings.wxml +++ b/pages/settings/settings.wxml @@ -140,6 +140,21 @@ + + + + 震动强度 + + + {{item.name}} + + diff --git a/pages/timer/timer.js b/pages/timer/timer.js index a5b3f3d..433587f 100644 --- a/pages/timer/timer.js +++ b/pages/timer/timer.js @@ -132,13 +132,27 @@ Page({ const s = storage.getSettings() const { remaining, elapsed, duration } = tick const vibrate = (n, ms) => { - if (!s.vibrate) return + // `=== false` (not `!s.vibrate`) so an undefined field (legacy users + // whose settings predate the toggle) is treated as ON, matching the + // voiceGuide check below. `!s.vibrate` used to see undefined as falsy + // and silently skip vibration until the user toggled the switch. + if (s.vibrate === false) return + const intensity = s.vibrateIntensity || 'heavy' + // light/medium = vibrateShort(type); heavy = vibrateLong(400ms). + // vibrateLong is the most reliable on iOS real devices; the short + // types are nicer but may be silent on some devices - user picks. + const doVibrate = () => { + const fail = (err) => console.warn('[vibrate] failed:', err.errMsg || err) + if (intensity === 'light') wx.vibrateShort({ type: 'light', fail }) + else if (intensity === 'medium') wx.vibrateShort({ type: 'medium', fail }) + else wx.vibrateLong({ fail }) + } try { for (let i = 0; i < n; i++) { // Track timers so pause/stop/unload can cancel pending bursts // instead of firing vibrations on a page that's already torn down. const id = setTimeout(() => { - wx.vibrateShort() + doVibrate() const idx = this._vibrateTimers.indexOf(id) if (idx > -1) this._vibrateTimers.splice(idx, 1) }, i * (ms + 30)) diff --git a/utils/storage.js b/utils/storage.js index 9ce82cb..a59a2e2 100644 --- a/utils/storage.js +++ b/utils/storage.js @@ -170,13 +170,21 @@ const getSettings = () => { // Backfill voiceGender for existing users (added with the male/female // voice option). Defaults to female, the prior behavior. if (!s.voiceGender) s.voiceGender = 'female' + // Backfill vibrate/voiceGuide for users whose settings predate these + // toggles. Without this, s.vibrate is undefined and `!s.vibrate` in + // the timer reads it as "off" - vibration silently no-ops until the + // user manually toggles the switch (which writes a real boolean). + if (s.vibrate == null) s.vibrate = true + if (s.voiceGuide == null) s.voiceGuide = true + if (!s.vibrateIntensity) s.vibrateIntensity = 'heavy' return s } return { planId: 'beginner', voiceGuide: true, vibrate: true, - voiceGender: 'female' + voiceGender: 'female', + vibrateIntensity: 'heavy' } }