|
|
@@ -6,6 +6,7 @@ import {
|
|
|
type MapEngineViewState,
|
|
|
} from '../../engine/map/mapEngine'
|
|
|
import { loadRemoteMapConfig } from '../../utils/remoteMapConfig'
|
|
|
+import { type AnimationLevel } from '../../utils/animationLevel'
|
|
|
type CompassTickData = {
|
|
|
angle: number
|
|
|
long: boolean
|
|
|
@@ -31,9 +32,17 @@ type ScaleRulerMajorMarkData = {
|
|
|
type SideButtonMode = 'all' | 'left' | 'right' | 'hidden'
|
|
|
type SideActionButtonState = 'muted' | 'default' | 'active'
|
|
|
type CenterScaleRulerAnchorMode = 'screen-center' | 'compass-center'
|
|
|
+type UserNorthReferenceMode = 'magnetic' | 'true'
|
|
|
+type StoredUserSettings = {
|
|
|
+ animationLevel?: AnimationLevel
|
|
|
+ northReferenceMode?: UserNorthReferenceMode
|
|
|
+ showCenterScaleRuler?: boolean
|
|
|
+ centerScaleRulerAnchorMode?: CenterScaleRulerAnchorMode
|
|
|
+}
|
|
|
type MapPageData = MapEngineViewState & {
|
|
|
showDebugPanel: boolean
|
|
|
showGameInfoPanel: boolean
|
|
|
+ showSystemSettingsPanel: boolean
|
|
|
showCenterScaleRuler: boolean
|
|
|
showPunchHintBanner: boolean
|
|
|
centerScaleRulerAnchorMode: CenterScaleRulerAnchorMode
|
|
|
@@ -52,6 +61,10 @@ type MapPageData = MapEngineViewState & {
|
|
|
panelDistanceValueText: string
|
|
|
panelProgressText: string
|
|
|
panelSpeedValueText: string
|
|
|
+ panelTimerFxClass: string
|
|
|
+ panelMileageFxClass: string
|
|
|
+ panelSpeedFxClass: string
|
|
|
+ panelHeartRateFxClass: string
|
|
|
compassTicks: CompassTickData[]
|
|
|
compassLabels: CompassLabelData[]
|
|
|
sideButtonMode: SideButtonMode
|
|
|
@@ -59,6 +72,7 @@ type MapPageData = MapEngineViewState & {
|
|
|
sideButton2Class: string
|
|
|
sideButton4Class: string
|
|
|
sideButton11Class: string
|
|
|
+ sideButton12Class: string
|
|
|
sideButton13Class: string
|
|
|
sideButton14Class: string
|
|
|
sideButton16Class: string
|
|
|
@@ -75,7 +89,8 @@ type MapPageData = MapEngineViewState & {
|
|
|
showRightButtonGroups: boolean
|
|
|
showBottomDebugButton: boolean
|
|
|
}
|
|
|
-const INTERNAL_BUILD_VERSION = 'map-build-261'
|
|
|
+const INTERNAL_BUILD_VERSION = 'map-build-282'
|
|
|
+const USER_SETTINGS_STORAGE_KEY = 'cmr_user_settings_v1'
|
|
|
const CLASSIC_REMOTE_GAME_CONFIG_URL = 'https://oss-mbh5.colormaprun.com/gotomars/event/classic-sequential.json'
|
|
|
const SCORE_O_REMOTE_GAME_CONFIG_URL = 'https://oss-mbh5.colormaprun.com/gotomars/event/score-o.json'
|
|
|
const PUNCH_HINT_AUTO_HIDE_MS = 30000
|
|
|
@@ -83,7 +98,43 @@ let mapEngine: MapEngine | null = null
|
|
|
let stageCanvasAttached = false
|
|
|
let gameInfoPanelSyncTimer = 0
|
|
|
let centerScaleRulerSyncTimer = 0
|
|
|
+let centerScaleRulerUpdateTimer = 0
|
|
|
let punchHintDismissTimer = 0
|
|
|
+let panelTimerFxTimer = 0
|
|
|
+let panelMileageFxTimer = 0
|
|
|
+let panelSpeedFxTimer = 0
|
|
|
+let panelHeartRateFxTimer = 0
|
|
|
+let lastCenterScaleRulerStablePatch: Pick<
|
|
|
+ MapPageData,
|
|
|
+ | 'centerScaleRulerVisible'
|
|
|
+ | 'centerScaleRulerCenterXPx'
|
|
|
+ | 'centerScaleRulerZeroYPx'
|
|
|
+ | 'centerScaleRulerHeightPx'
|
|
|
+ | 'centerScaleRulerAxisBottomPx'
|
|
|
+ | 'centerScaleRulerZeroVisible'
|
|
|
+ | 'centerScaleRulerZeroLabel'
|
|
|
+ | 'centerScaleRulerMinorTicks'
|
|
|
+ | 'centerScaleRulerMajorMarks'
|
|
|
+> = {
|
|
|
+ centerScaleRulerVisible: false,
|
|
|
+ centerScaleRulerCenterXPx: 0,
|
|
|
+ centerScaleRulerZeroYPx: 0,
|
|
|
+ centerScaleRulerHeightPx: 0,
|
|
|
+ centerScaleRulerAxisBottomPx: 0,
|
|
|
+ centerScaleRulerZeroVisible: false,
|
|
|
+ centerScaleRulerZeroLabel: '0 m',
|
|
|
+ centerScaleRulerMinorTicks: [],
|
|
|
+ centerScaleRulerMajorMarks: [],
|
|
|
+}
|
|
|
+let centerScaleRulerInputCache: Partial<Pick<
|
|
|
+ MapPageData,
|
|
|
+ 'stageWidth'
|
|
|
+ | 'stageHeight'
|
|
|
+ | 'zoom'
|
|
|
+ | 'centerTileY'
|
|
|
+ | 'tileSizePx'
|
|
|
+ | 'previewScale'
|
|
|
+>> = {}
|
|
|
|
|
|
const DEBUG_ONLY_VIEW_KEYS = new Set<string>([
|
|
|
'buildVersion',
|
|
|
@@ -93,14 +144,15 @@ const DEBUG_ONLY_VIEW_KEYS = new Set<string>([
|
|
|
'mapReadyText',
|
|
|
'mapName',
|
|
|
'configStatusText',
|
|
|
- 'sensorHeadingText',
|
|
|
'deviceHeadingText',
|
|
|
'devicePoseText',
|
|
|
'headingConfidenceText',
|
|
|
'accelerometerText',
|
|
|
'gyroscopeText',
|
|
|
'deviceMotionText',
|
|
|
- 'compassDeclinationText',
|
|
|
+ 'compassSourceText',
|
|
|
+ 'compassTuningProfile',
|
|
|
+ 'compassTuningProfileText',
|
|
|
'northReferenceButtonText',
|
|
|
'autoRotateSourceText',
|
|
|
'autoRotateCalibrationText',
|
|
|
@@ -148,6 +200,15 @@ const CENTER_SCALE_RULER_DEP_KEYS = new Set<string>([
|
|
|
'previewScale',
|
|
|
])
|
|
|
|
|
|
+const CENTER_SCALE_RULER_CACHE_KEYS: Array<keyof typeof centerScaleRulerInputCache> = [
|
|
|
+ 'stageWidth',
|
|
|
+ 'stageHeight',
|
|
|
+ 'zoom',
|
|
|
+ 'centerTileY',
|
|
|
+ 'tileSizePx',
|
|
|
+ 'previewScale',
|
|
|
+]
|
|
|
+
|
|
|
const RULER_ONLY_VIEW_KEYS = new Set<string>([
|
|
|
'zoom',
|
|
|
'centerTileX',
|
|
|
@@ -213,12 +274,83 @@ function clearCenterScaleRulerSyncTimer() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+function clearCenterScaleRulerUpdateTimer() {
|
|
|
+ if (centerScaleRulerUpdateTimer) {
|
|
|
+ clearTimeout(centerScaleRulerUpdateTimer)
|
|
|
+ centerScaleRulerUpdateTimer = 0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
function clearPunchHintDismissTimer() {
|
|
|
if (punchHintDismissTimer) {
|
|
|
clearTimeout(punchHintDismissTimer)
|
|
|
punchHintDismissTimer = 0
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+function clearHudFxTimer(key: 'timer' | 'mileage' | 'speed' | 'heartRate') {
|
|
|
+ const timerMap = {
|
|
|
+ timer: panelTimerFxTimer,
|
|
|
+ mileage: panelMileageFxTimer,
|
|
|
+ speed: panelSpeedFxTimer,
|
|
|
+ heartRate: panelHeartRateFxTimer,
|
|
|
+ }
|
|
|
+ const timer = timerMap[key]
|
|
|
+ if (timer) {
|
|
|
+ clearTimeout(timer)
|
|
|
+ }
|
|
|
+ if (key === 'timer') {
|
|
|
+ panelTimerFxTimer = 0
|
|
|
+ } else if (key === 'mileage') {
|
|
|
+ panelMileageFxTimer = 0
|
|
|
+ } else if (key === 'speed') {
|
|
|
+ panelSpeedFxTimer = 0
|
|
|
+ } else {
|
|
|
+ panelHeartRateFxTimer = 0
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function updateCenterScaleRulerInputCache(patch: Partial<MapPageData>) {
|
|
|
+ for (const key of CENTER_SCALE_RULER_CACHE_KEYS) {
|
|
|
+ if (Object.prototype.hasOwnProperty.call(patch, key)) {
|
|
|
+ ;(centerScaleRulerInputCache as Record<string, unknown>)[key] =
|
|
|
+ (patch as Record<string, unknown>)[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function loadStoredUserSettings(): StoredUserSettings {
|
|
|
+ try {
|
|
|
+ const stored = wx.getStorageSync(USER_SETTINGS_STORAGE_KEY)
|
|
|
+ if (!stored || typeof stored !== 'object') {
|
|
|
+ return {}
|
|
|
+ }
|
|
|
+
|
|
|
+ const normalized = stored as Record<string, unknown>
|
|
|
+ const settings: StoredUserSettings = {}
|
|
|
+ if (normalized.animationLevel === 'standard' || normalized.animationLevel === 'lite') {
|
|
|
+ settings.animationLevel = normalized.animationLevel
|
|
|
+ }
|
|
|
+ if (normalized.northReferenceMode === 'magnetic' || normalized.northReferenceMode === 'true') {
|
|
|
+ settings.northReferenceMode = normalized.northReferenceMode
|
|
|
+ }
|
|
|
+ if (typeof normalized.showCenterScaleRuler === 'boolean') {
|
|
|
+ settings.showCenterScaleRuler = normalized.showCenterScaleRuler
|
|
|
+ }
|
|
|
+ if (normalized.centerScaleRulerAnchorMode === 'screen-center' || normalized.centerScaleRulerAnchorMode === 'compass-center') {
|
|
|
+ settings.centerScaleRulerAnchorMode = normalized.centerScaleRulerAnchorMode
|
|
|
+ }
|
|
|
+ return settings
|
|
|
+ } catch {
|
|
|
+ return {}
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function persistStoredUserSettings(settings: StoredUserSettings) {
|
|
|
+ try {
|
|
|
+ wx.setStorageSync(USER_SETTINGS_STORAGE_KEY, settings)
|
|
|
+ } catch {}
|
|
|
+}
|
|
|
function buildSideButtonVisibility(mode: SideButtonMode) {
|
|
|
return {
|
|
|
sideButtonMode: mode,
|
|
|
@@ -296,7 +428,7 @@ function getSideActionButtonClass(state: SideActionButtonState): string {
|
|
|
return 'map-side-button map-side-button--default'
|
|
|
}
|
|
|
|
|
|
-function buildSideButtonState(data: Pick<MapPageData, 'sideButtonMode' | 'showGameInfoPanel' | 'showCenterScaleRuler' | 'centerScaleRulerAnchorMode' | 'skipButtonEnabled' | 'gameSessionStatus' | 'gpsLockEnabled' | 'gpsLockAvailable'>) {
|
|
|
+function buildSideButtonState(data: Pick<MapPageData, 'sideButtonMode' | 'showGameInfoPanel' | 'showSystemSettingsPanel' | 'showCenterScaleRuler' | 'centerScaleRulerAnchorMode' | 'skipButtonEnabled' | 'gameSessionStatus' | 'gpsLockEnabled' | 'gpsLockAvailable'>) {
|
|
|
const sideButton2State: SideActionButtonState = !data.gpsLockAvailable
|
|
|
? 'muted'
|
|
|
: data.gpsLockEnabled
|
|
|
@@ -304,6 +436,7 @@ function buildSideButtonState(data: Pick<MapPageData, 'sideButtonMode' | 'showGa
|
|
|
: 'default'
|
|
|
const sideButton4State: SideActionButtonState = data.gameSessionStatus === 'idle' ? 'default' : 'active'
|
|
|
const sideButton11State: SideActionButtonState = data.showGameInfoPanel ? 'active' : 'default'
|
|
|
+ const sideButton12State: SideActionButtonState = data.showSystemSettingsPanel ? 'active' : 'default'
|
|
|
const sideButton13State: SideActionButtonState = data.showCenterScaleRuler ? 'active' : 'default'
|
|
|
const sideButton14State: SideActionButtonState = !data.showCenterScaleRuler
|
|
|
? 'muted'
|
|
|
@@ -317,6 +450,7 @@ function buildSideButtonState(data: Pick<MapPageData, 'sideButtonMode' | 'showGa
|
|
|
sideButton2Class: getSideActionButtonClass(sideButton2State),
|
|
|
sideButton4Class: getSideActionButtonClass(sideButton4State),
|
|
|
sideButton11Class: getSideActionButtonClass(sideButton11State),
|
|
|
+ sideButton12Class: getSideActionButtonClass(sideButton12State),
|
|
|
sideButton13Class: getSideActionButtonClass(sideButton13State),
|
|
|
sideButton14Class: getSideActionButtonClass(sideButton14State),
|
|
|
sideButton16Class: getSideActionButtonClass(sideButton16State),
|
|
|
@@ -367,7 +501,7 @@ function formatScaleDistanceLabel(distanceMeters: number): string {
|
|
|
|
|
|
function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRuler' | 'centerScaleRulerAnchorMode' | 'stageWidth' | 'stageHeight' | 'topInsetHeight' | 'zoom' | 'centerTileY' | 'tileSizePx' | 'previewScale'>) {
|
|
|
if (!data.showCenterScaleRuler) {
|
|
|
- return {
|
|
|
+ lastCenterScaleRulerStablePatch = {
|
|
|
centerScaleRulerVisible: false,
|
|
|
centerScaleRulerCenterXPx: 0,
|
|
|
centerScaleRulerZeroYPx: 0,
|
|
|
@@ -378,20 +512,11 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
|
|
centerScaleRulerMinorTicks: [] as ScaleRulerMinorTickData[],
|
|
|
centerScaleRulerMajorMarks: [] as ScaleRulerMajorMarkData[],
|
|
|
}
|
|
|
+ return { ...lastCenterScaleRulerStablePatch }
|
|
|
}
|
|
|
|
|
|
if (!data.stageWidth || !data.stageHeight) {
|
|
|
- return {
|
|
|
- centerScaleRulerVisible: false,
|
|
|
- centerScaleRulerCenterXPx: 0,
|
|
|
- centerScaleRulerZeroYPx: 0,
|
|
|
- centerScaleRulerHeightPx: 0,
|
|
|
- centerScaleRulerAxisBottomPx: 0,
|
|
|
- centerScaleRulerZeroVisible: false,
|
|
|
- centerScaleRulerZeroLabel: '0 m',
|
|
|
- centerScaleRulerMinorTicks: [] as ScaleRulerMinorTickData[],
|
|
|
- centerScaleRulerMajorMarks: [] as ScaleRulerMajorMarkData[],
|
|
|
- }
|
|
|
+ return { ...lastCenterScaleRulerStablePatch }
|
|
|
}
|
|
|
|
|
|
const topPadding = 12
|
|
|
@@ -414,15 +539,13 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
|
|
|| !Number.isFinite(data.centerTileY)
|
|
|
) {
|
|
|
return {
|
|
|
+ ...lastCenterScaleRulerStablePatch,
|
|
|
centerScaleRulerVisible: true,
|
|
|
centerScaleRulerCenterXPx: Math.round(data.stageWidth / 2),
|
|
|
centerScaleRulerZeroYPx: zeroYPx,
|
|
|
- centerScaleRulerHeightPx: fallbackHeight,
|
|
|
+ centerScaleRulerHeightPx: lastCenterScaleRulerStablePatch.centerScaleRulerHeightPx || fallbackHeight,
|
|
|
centerScaleRulerAxisBottomPx: coveredBottomPx,
|
|
|
centerScaleRulerZeroVisible: data.centerScaleRulerAnchorMode !== 'compass-center',
|
|
|
- centerScaleRulerZeroLabel: '0 m',
|
|
|
- centerScaleRulerMinorTicks: [] as ScaleRulerMinorTickData[],
|
|
|
- centerScaleRulerMajorMarks: [] as ScaleRulerMajorMarkData[],
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -435,15 +558,13 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
|
|
|
|
|
if (!Number.isFinite(effectiveMetersPerPixel) || effectiveMetersPerPixel <= 0 || rulerHeight < 120) {
|
|
|
return {
|
|
|
+ ...lastCenterScaleRulerStablePatch,
|
|
|
centerScaleRulerVisible: true,
|
|
|
centerScaleRulerCenterXPx: Math.round(data.stageWidth / 2),
|
|
|
centerScaleRulerZeroYPx: zeroYPx,
|
|
|
- centerScaleRulerHeightPx: Math.max(rulerHeight, fallbackHeight),
|
|
|
+ centerScaleRulerHeightPx: lastCenterScaleRulerStablePatch.centerScaleRulerHeightPx || fallbackHeight,
|
|
|
centerScaleRulerAxisBottomPx: coveredBottomPx,
|
|
|
centerScaleRulerZeroVisible: data.centerScaleRulerAnchorMode !== 'compass-center',
|
|
|
- centerScaleRulerZeroLabel: '0 m',
|
|
|
- centerScaleRulerMinorTicks: [] as ScaleRulerMinorTickData[],
|
|
|
- centerScaleRulerMajorMarks: [] as ScaleRulerMajorMarkData[],
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -480,7 +601,7 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return {
|
|
|
+ lastCenterScaleRulerStablePatch = {
|
|
|
centerScaleRulerVisible: true,
|
|
|
centerScaleRulerCenterXPx: Math.round(data.stageWidth / 2),
|
|
|
centerScaleRulerZeroYPx: zeroYPx,
|
|
|
@@ -491,6 +612,7 @@ function buildCenterScaleRulerPatch(data: Pick<MapPageData, 'showCenterScaleRule
|
|
|
centerScaleRulerMinorTicks: minorTicks,
|
|
|
centerScaleRulerMajorMarks: majorMarks,
|
|
|
}
|
|
|
+ return { ...lastCenterScaleRulerStablePatch }
|
|
|
}
|
|
|
|
|
|
function buildEmptyGameInfoSnapshot(): MapEngineGameInfoSnapshot {
|
|
|
@@ -512,6 +634,7 @@ Page({
|
|
|
data: {
|
|
|
showDebugPanel: false,
|
|
|
showGameInfoPanel: false,
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
showCenterScaleRuler: false,
|
|
|
statusBarHeight: 0,
|
|
|
topInsetHeight: 12,
|
|
|
@@ -572,6 +695,9 @@ Page({
|
|
|
accelerometerText: '--',
|
|
|
gyroscopeText: '--',
|
|
|
deviceMotionText: '--',
|
|
|
+ compassSourceText: '无数据',
|
|
|
+ compassTuningProfile: 'balanced',
|
|
|
+ compassTuningProfileText: '平衡',
|
|
|
punchButtonText: '打点',
|
|
|
punchButtonEnabled: false,
|
|
|
skipButtonEnabled: false,
|
|
|
@@ -583,6 +709,8 @@ Page({
|
|
|
contentCardTitle: '',
|
|
|
contentCardBody: '',
|
|
|
punchButtonFxClass: '',
|
|
|
+ panelProgressFxClass: '',
|
|
|
+ panelDistanceFxClass: '',
|
|
|
punchFeedbackFxClass: '',
|
|
|
contentCardFxClass: '',
|
|
|
mapPulseVisible: false,
|
|
|
@@ -606,6 +734,7 @@ Page({
|
|
|
...buildSideButtonState({
|
|
|
sideButtonMode: 'left',
|
|
|
showGameInfoPanel: false,
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
showCenterScaleRuler: false,
|
|
|
centerScaleRulerAnchorMode: 'screen-center',
|
|
|
skipButtonEnabled: false,
|
|
|
@@ -649,7 +778,10 @@ Page({
|
|
|
nextData.mockHeartRateBridgeUrlDraft = nextPatch.mockHeartRateBridgeUrlText
|
|
|
}
|
|
|
|
|
|
+ updateCenterScaleRulerInputCache(nextPatch)
|
|
|
+
|
|
|
const mergedData = {
|
|
|
+ ...centerScaleRulerInputCache,
|
|
|
...this.data,
|
|
|
...nextData,
|
|
|
} as MapPageData
|
|
|
@@ -659,6 +791,7 @@ Page({
|
|
|
this.data.showCenterScaleRuler
|
|
|
&& hasAnyPatchKey(nextPatch as Record<string, unknown>, CENTER_SCALE_RULER_DEP_KEYS)
|
|
|
) {
|
|
|
+ clearCenterScaleRulerUpdateTimer()
|
|
|
Object.assign(derivedPatch, buildCenterScaleRulerPatch(mergedData))
|
|
|
}
|
|
|
|
|
|
@@ -685,6 +818,57 @@ Page({
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ const nextAnimationLevel = typeof nextPatch.animationLevel === 'string'
|
|
|
+ ? nextPatch.animationLevel
|
|
|
+ : this.data.animationLevel
|
|
|
+
|
|
|
+ if (nextAnimationLevel === 'lite') {
|
|
|
+ clearHudFxTimer('timer')
|
|
|
+ clearHudFxTimer('mileage')
|
|
|
+ clearHudFxTimer('speed')
|
|
|
+ clearHudFxTimer('heartRate')
|
|
|
+ nextData.panelTimerFxClass = ''
|
|
|
+ nextData.panelMileageFxClass = ''
|
|
|
+ nextData.panelSpeedFxClass = ''
|
|
|
+ nextData.panelHeartRateFxClass = ''
|
|
|
+ } else {
|
|
|
+ if (typeof nextPatch.panelTimerText === 'string' && nextPatch.panelTimerText !== this.data.panelTimerText && this.data.panelTimerText !== '00:00:00') {
|
|
|
+ clearHudFxTimer('timer')
|
|
|
+ nextData.panelTimerFxClass = 'race-panel__timer--fx-tick'
|
|
|
+ panelTimerFxTimer = setTimeout(() => {
|
|
|
+ panelTimerFxTimer = 0
|
|
|
+ this.setData({ panelTimerFxClass: '' })
|
|
|
+ }, 320) as unknown as number
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof nextPatch.panelMileageText === 'string' && nextPatch.panelMileageText !== this.data.panelMileageText && this.data.panelMileageText !== '0m') {
|
|
|
+ clearHudFxTimer('mileage')
|
|
|
+ nextData.panelMileageFxClass = 'race-panel__mileage-wrap--fx-update'
|
|
|
+ panelMileageFxTimer = setTimeout(() => {
|
|
|
+ panelMileageFxTimer = 0
|
|
|
+ this.setData({ panelMileageFxClass: '' })
|
|
|
+ }, 360) as unknown as number
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof nextPatch.panelSpeedValueText === 'string' && nextPatch.panelSpeedValueText !== this.data.panelSpeedValueText && this.data.panelSpeedValueText !== '0') {
|
|
|
+ clearHudFxTimer('speed')
|
|
|
+ nextData.panelSpeedFxClass = 'race-panel__metric-group--fx-speed-update'
|
|
|
+ panelSpeedFxTimer = setTimeout(() => {
|
|
|
+ panelSpeedFxTimer = 0
|
|
|
+ this.setData({ panelSpeedFxClass: '' })
|
|
|
+ }, 360) as unknown as number
|
|
|
+ }
|
|
|
+
|
|
|
+ if (typeof nextPatch.panelHeartRateValueText === 'string' && nextPatch.panelHeartRateValueText !== this.data.panelHeartRateValueText && this.data.panelHeartRateValueText !== '--') {
|
|
|
+ clearHudFxTimer('heartRate')
|
|
|
+ nextData.panelHeartRateFxClass = 'race-panel__metric-group--fx-heart-rate-update'
|
|
|
+ panelHeartRateFxTimer = setTimeout(() => {
|
|
|
+ panelHeartRateFxTimer = 0
|
|
|
+ this.setData({ panelHeartRateFxClass: '' })
|
|
|
+ }, 400) as unknown as number
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (Object.keys(nextData).length || Object.keys(derivedPatch).length) {
|
|
|
this.setData({
|
|
|
...nextData,
|
|
|
@@ -698,22 +882,46 @@ Page({
|
|
|
},
|
|
|
})
|
|
|
|
|
|
+ const storedUserSettings = loadStoredUserSettings()
|
|
|
+ if (storedUserSettings.animationLevel) {
|
|
|
+ mapEngine.handleSetAnimationLevel(storedUserSettings.animationLevel)
|
|
|
+ }
|
|
|
+ if (storedUserSettings.northReferenceMode) {
|
|
|
+ mapEngine.handleSetNorthReferenceMode(storedUserSettings.northReferenceMode)
|
|
|
+ }
|
|
|
+
|
|
|
mapEngine.setDiagnosticUiEnabled(false)
|
|
|
+ centerScaleRulerInputCache = {
|
|
|
+ stageWidth: 0,
|
|
|
+ stageHeight: 0,
|
|
|
+ zoom: 0,
|
|
|
+ centerTileY: 0,
|
|
|
+ tileSizePx: 0,
|
|
|
+ previewScale: 1,
|
|
|
+ }
|
|
|
+
|
|
|
+ const initialShowCenterScaleRuler = !!storedUserSettings.showCenterScaleRuler
|
|
|
+ const initialCenterScaleRulerAnchorMode = storedUserSettings.centerScaleRulerAnchorMode || 'screen-center'
|
|
|
|
|
|
this.setData({
|
|
|
...mapEngine.getInitialData(),
|
|
|
showDebugPanel: false,
|
|
|
showGameInfoPanel: false,
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
+ showCenterScaleRuler: initialShowCenterScaleRuler,
|
|
|
statusBarHeight,
|
|
|
topInsetHeight: Math.max(statusBarHeight + 12, menuButtonBottom + 20),
|
|
|
hudPanelIndex: 0,
|
|
|
configSourceText: '顺序赛配置',
|
|
|
+ centerScaleRulerAnchorMode: initialCenterScaleRulerAnchorMode,
|
|
|
gameInfoTitle: '当前游戏',
|
|
|
gameInfoSubtitle: '未开始',
|
|
|
gameInfoLocalRows: [],
|
|
|
gameInfoGlobalRows: buildEmptyGameInfoSnapshot().globalRows,
|
|
|
panelTimerText: '00:00:00',
|
|
|
+ panelTimerFxClass: '',
|
|
|
panelMileageText: '0m',
|
|
|
+ panelMileageFxClass: '',
|
|
|
panelActionTagText: '目标',
|
|
|
panelDistanceTagText: '点距',
|
|
|
panelDistanceValueText: '--',
|
|
|
@@ -740,6 +948,7 @@ Page({
|
|
|
mockHeartRateBridgeUrlDraft: 'wss://gs.gotomars.xyz/mock-gps',
|
|
|
mockHeartRateText: '--',
|
|
|
panelSpeedValueText: '0',
|
|
|
+ panelSpeedFxClass: '',
|
|
|
panelTelemetryTone: 'blue',
|
|
|
panelHeartRateZoneNameText: '--',
|
|
|
panelHeartRateZoneRangeText: '',
|
|
|
@@ -747,6 +956,7 @@ Page({
|
|
|
heartRateStatusText: '心率带未连接',
|
|
|
heartRateDeviceText: '--',
|
|
|
panelHeartRateValueText: '--',
|
|
|
+ panelHeartRateFxClass: '',
|
|
|
panelHeartRateUnitText: '',
|
|
|
panelCaloriesValueText: '0',
|
|
|
panelCaloriesUnitText: 'kcal',
|
|
|
@@ -760,6 +970,9 @@ Page({
|
|
|
accelerometerText: '--',
|
|
|
gyroscopeText: '--',
|
|
|
deviceMotionText: '--',
|
|
|
+ compassSourceText: '无数据',
|
|
|
+ compassTuningProfile: 'balanced',
|
|
|
+ compassTuningProfileText: '平衡',
|
|
|
punchButtonText: '打点',
|
|
|
punchButtonEnabled: false,
|
|
|
skipButtonEnabled: false,
|
|
|
@@ -771,6 +984,8 @@ Page({
|
|
|
contentCardTitle: '',
|
|
|
contentCardBody: '',
|
|
|
punchButtonFxClass: '',
|
|
|
+ panelProgressFxClass: '',
|
|
|
+ panelDistanceFxClass: '',
|
|
|
punchFeedbackFxClass: '',
|
|
|
contentCardFxClass: '',
|
|
|
mapPulseVisible: false,
|
|
|
@@ -785,8 +1000,9 @@ Page({
|
|
|
...buildSideButtonState({
|
|
|
sideButtonMode: 'left',
|
|
|
showGameInfoPanel: false,
|
|
|
- showCenterScaleRuler: false,
|
|
|
- centerScaleRulerAnchorMode: 'screen-center',
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
+ showCenterScaleRuler: initialShowCenterScaleRuler,
|
|
|
+ centerScaleRulerAnchorMode: initialCenterScaleRulerAnchorMode,
|
|
|
skipButtonEnabled: false,
|
|
|
gameSessionStatus: 'idle',
|
|
|
gpsLockEnabled: false,
|
|
|
@@ -794,8 +1010,8 @@ Page({
|
|
|
}),
|
|
|
...buildCenterScaleRulerPatch({
|
|
|
...(mapEngine.getInitialData() as MapPageData),
|
|
|
- showCenterScaleRuler: false,
|
|
|
- centerScaleRulerAnchorMode: 'screen-center',
|
|
|
+ showCenterScaleRuler: initialShowCenterScaleRuler,
|
|
|
+ centerScaleRulerAnchorMode: initialCenterScaleRulerAnchorMode,
|
|
|
stageWidth: 0,
|
|
|
stageHeight: 0,
|
|
|
topInsetHeight: Math.max(statusBarHeight + 12, menuButtonBottom + 20),
|
|
|
@@ -827,7 +1043,12 @@ Page({
|
|
|
onUnload() {
|
|
|
clearGameInfoPanelSyncTimer()
|
|
|
clearCenterScaleRulerSyncTimer()
|
|
|
+ clearCenterScaleRulerUpdateTimer()
|
|
|
clearPunchHintDismissTimer()
|
|
|
+ clearHudFxTimer('timer')
|
|
|
+ clearHudFxTimer('mileage')
|
|
|
+ clearHudFxTimer('speed')
|
|
|
+ clearHudFxTimer('heartRate')
|
|
|
if (mapEngine) {
|
|
|
mapEngine.destroy()
|
|
|
mapEngine = null
|
|
|
@@ -997,6 +1218,24 @@ Page({
|
|
|
}
|
|
|
},
|
|
|
|
|
|
+ handleSetCompassTuningSmooth() {
|
|
|
+ if (mapEngine) {
|
|
|
+ mapEngine.handleSetCompassTuningProfile('smooth')
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSetCompassTuningBalanced() {
|
|
|
+ if (mapEngine) {
|
|
|
+ mapEngine.handleSetCompassTuningProfile('balanced')
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSetCompassTuningResponsive() {
|
|
|
+ if (mapEngine) {
|
|
|
+ mapEngine.handleSetCompassTuningProfile('responsive')
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
handleAutoRotateCalibrate() {
|
|
|
if (mapEngine) {
|
|
|
mapEngine.handleAutoRotateCalibrate()
|
|
|
@@ -1260,10 +1499,12 @@ Page({
|
|
|
this.syncGameInfoPanelSnapshot()
|
|
|
this.setData({
|
|
|
showDebugPanel: false,
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
showGameInfoPanel: true,
|
|
|
...buildSideButtonState({
|
|
|
sideButtonMode: this.data.sideButtonMode,
|
|
|
showGameInfoPanel: true,
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
skipButtonEnabled: this.data.skipButtonEnabled,
|
|
|
@@ -1281,6 +1522,7 @@ Page({
|
|
|
...buildSideButtonState({
|
|
|
sideButtonMode: this.data.sideButtonMode,
|
|
|
showGameInfoPanel: false,
|
|
|
+ showSystemSettingsPanel: this.data.showSystemSettingsPanel,
|
|
|
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
skipButtonEnabled: this.data.skipButtonEnabled,
|
|
|
@@ -1293,6 +1535,89 @@ Page({
|
|
|
|
|
|
handleGameInfoPanelTap() {},
|
|
|
|
|
|
+ handleOpenSystemSettingsPanel() {
|
|
|
+ clearGameInfoPanelSyncTimer()
|
|
|
+ this.setData({
|
|
|
+ showDebugPanel: false,
|
|
|
+ showGameInfoPanel: false,
|
|
|
+ showSystemSettingsPanel: true,
|
|
|
+ ...buildSideButtonState({
|
|
|
+ sideButtonMode: this.data.sideButtonMode,
|
|
|
+ showGameInfoPanel: false,
|
|
|
+ showSystemSettingsPanel: true,
|
|
|
+ showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
+ centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
+ skipButtonEnabled: this.data.skipButtonEnabled,
|
|
|
+ gameSessionStatus: this.data.gameSessionStatus,
|
|
|
+ gpsLockEnabled: this.data.gpsLockEnabled,
|
|
|
+ gpsLockAvailable: this.data.gpsLockAvailable,
|
|
|
+ }),
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ handleCloseSystemSettingsPanel() {
|
|
|
+ this.setData({
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
+ ...buildSideButtonState({
|
|
|
+ sideButtonMode: this.data.sideButtonMode,
|
|
|
+ showGameInfoPanel: this.data.showGameInfoPanel,
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
+ showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
+ centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
+ skipButtonEnabled: this.data.skipButtonEnabled,
|
|
|
+ gameSessionStatus: this.data.gameSessionStatus,
|
|
|
+ gpsLockEnabled: this.data.gpsLockEnabled,
|
|
|
+ gpsLockAvailable: this.data.gpsLockAvailable,
|
|
|
+ }),
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSystemSettingsPanelTap() {},
|
|
|
+
|
|
|
+ handleSetAnimationLevelStandard() {
|
|
|
+ if (!mapEngine) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ mapEngine.handleSetAnimationLevel('standard')
|
|
|
+ persistStoredUserSettings({
|
|
|
+ ...loadStoredUserSettings(),
|
|
|
+ animationLevel: 'standard',
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSetAnimationLevelLite() {
|
|
|
+ if (!mapEngine) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ mapEngine.handleSetAnimationLevel('lite')
|
|
|
+ persistStoredUserSettings({
|
|
|
+ ...loadStoredUserSettings(),
|
|
|
+ animationLevel: 'lite',
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSetNorthReferenceMagnetic() {
|
|
|
+ if (!mapEngine) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ mapEngine.handleSetNorthReferenceMode('magnetic')
|
|
|
+ persistStoredUserSettings({
|
|
|
+ ...loadStoredUserSettings(),
|
|
|
+ northReferenceMode: 'magnetic',
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSetNorthReferenceTrue() {
|
|
|
+ if (!mapEngine) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ mapEngine.handleSetNorthReferenceMode('true')
|
|
|
+ persistStoredUserSettings({
|
|
|
+ ...loadStoredUserSettings(),
|
|
|
+ northReferenceMode: 'true',
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
handleOverlayTouch() {},
|
|
|
|
|
|
handlePunchAction() {
|
|
|
@@ -1318,6 +1643,8 @@ Page({
|
|
|
})
|
|
|
},
|
|
|
|
|
|
+ handlePunchHintTap() {},
|
|
|
+
|
|
|
handleHudPanelChange(event: WechatMiniprogram.CustomEvent<{ current: number }>) {
|
|
|
this.setData({
|
|
|
hudPanelIndex: event.detail.current || 0,
|
|
|
@@ -1331,6 +1658,7 @@ Page({
|
|
|
...buildSideButtonState({
|
|
|
sideButtonMode: nextMode,
|
|
|
showGameInfoPanel: this.data.showGameInfoPanel,
|
|
|
+ showSystemSettingsPanel: this.data.showSystemSettingsPanel,
|
|
|
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
skipButtonEnabled: this.data.skipButtonEnabled,
|
|
|
@@ -1368,9 +1696,11 @@ Page({
|
|
|
this.setData({
|
|
|
showDebugPanel: nextShowDebugPanel,
|
|
|
showGameInfoPanel: false,
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
...buildSideButtonState({
|
|
|
sideButtonMode: this.data.sideButtonMode,
|
|
|
showGameInfoPanel: false,
|
|
|
+ showSystemSettingsPanel: false,
|
|
|
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
skipButtonEnabled: this.data.skipButtonEnabled,
|
|
|
@@ -1390,6 +1720,7 @@ Page({
|
|
|
...buildSideButtonState({
|
|
|
sideButtonMode: this.data.sideButtonMode,
|
|
|
showGameInfoPanel: this.data.showGameInfoPanel,
|
|
|
+ showSystemSettingsPanel: this.data.showSystemSettingsPanel,
|
|
|
showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
skipButtonEnabled: this.data.skipButtonEnabled,
|
|
|
@@ -1400,25 +1731,29 @@ Page({
|
|
|
})
|
|
|
},
|
|
|
|
|
|
- handleToggleCenterScaleRuler() {
|
|
|
- const nextEnabled = !this.data.showCenterScaleRuler
|
|
|
+ applyCenterScaleRulerSettings(nextEnabled: boolean, nextAnchorMode: CenterScaleRulerAnchorMode) {
|
|
|
this.data.showCenterScaleRuler = nextEnabled
|
|
|
+ this.data.centerScaleRulerAnchorMode = nextAnchorMode
|
|
|
clearCenterScaleRulerSyncTimer()
|
|
|
+ clearCenterScaleRulerUpdateTimer()
|
|
|
|
|
|
const syncRulerFromEngine = () => {
|
|
|
if (!mapEngine) {
|
|
|
return
|
|
|
}
|
|
|
const engineSnapshot = mapEngine.getInitialData() as Partial<MapPageData>
|
|
|
+ updateCenterScaleRulerInputCache(engineSnapshot)
|
|
|
const mergedData = {
|
|
|
- ...engineSnapshot,
|
|
|
+ ...centerScaleRulerInputCache,
|
|
|
...this.data,
|
|
|
showCenterScaleRuler: nextEnabled,
|
|
|
+ centerScaleRulerAnchorMode: nextAnchorMode,
|
|
|
} as MapPageData
|
|
|
|
|
|
this.setData({
|
|
|
...filterDebugOnlyPatch(engineSnapshot, this.data.showDebugPanel, nextEnabled),
|
|
|
showCenterScaleRuler: nextEnabled,
|
|
|
+ centerScaleRulerAnchorMode: nextAnchorMode,
|
|
|
...buildCenterScaleRulerPatch(mergedData),
|
|
|
...buildSideButtonState(mergedData),
|
|
|
})
|
|
|
@@ -1431,9 +1766,11 @@ Page({
|
|
|
|
|
|
this.setData({
|
|
|
showCenterScaleRuler: true,
|
|
|
+ centerScaleRulerAnchorMode: nextAnchorMode,
|
|
|
...buildSideButtonState({
|
|
|
...this.data,
|
|
|
showCenterScaleRuler: true,
|
|
|
+ centerScaleRulerAnchorMode: nextAnchorMode,
|
|
|
} as MapPageData),
|
|
|
})
|
|
|
|
|
|
@@ -1450,6 +1787,42 @@ Page({
|
|
|
}, 96) as unknown as number
|
|
|
},
|
|
|
|
|
|
+ handleSetCenterScaleRulerVisibleOn() {
|
|
|
+ this.applyCenterScaleRulerSettings(true, this.data.centerScaleRulerAnchorMode)
|
|
|
+ persistStoredUserSettings({
|
|
|
+ ...loadStoredUserSettings(),
|
|
|
+ showCenterScaleRuler: true,
|
|
|
+ centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSetCenterScaleRulerVisibleOff() {
|
|
|
+ this.applyCenterScaleRulerSettings(false, this.data.centerScaleRulerAnchorMode)
|
|
|
+ persistStoredUserSettings({
|
|
|
+ ...loadStoredUserSettings(),
|
|
|
+ showCenterScaleRuler: false,
|
|
|
+ centerScaleRulerAnchorMode: this.data.centerScaleRulerAnchorMode,
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSetCenterScaleRulerAnchorScreenCenter() {
|
|
|
+ this.applyCenterScaleRulerSettings(this.data.showCenterScaleRuler, 'screen-center')
|
|
|
+ persistStoredUserSettings({
|
|
|
+ ...loadStoredUserSettings(),
|
|
|
+ showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
+ centerScaleRulerAnchorMode: 'screen-center',
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSetCenterScaleRulerAnchorCompassCenter() {
|
|
|
+ this.applyCenterScaleRulerSettings(this.data.showCenterScaleRuler, 'compass-center')
|
|
|
+ persistStoredUserSettings({
|
|
|
+ ...loadStoredUserSettings(),
|
|
|
+ showCenterScaleRuler: this.data.showCenterScaleRuler,
|
|
|
+ centerScaleRulerAnchorMode: 'compass-center',
|
|
|
+ })
|
|
|
+ },
|
|
|
+
|
|
|
handleToggleCenterScaleRulerAnchor() {
|
|
|
if (!this.data.showCenterScaleRuler) {
|
|
|
return
|
|
|
@@ -1459,9 +1832,10 @@ Page({
|
|
|
? 'compass-center'
|
|
|
: 'screen-center'
|
|
|
const engineSnapshot = mapEngine ? (mapEngine.getInitialData() as Partial<MapPageData>) : {}
|
|
|
+ updateCenterScaleRulerInputCache(engineSnapshot)
|
|
|
this.data.centerScaleRulerAnchorMode = nextAnchorMode
|
|
|
const mergedData = {
|
|
|
- ...engineSnapshot,
|
|
|
+ ...centerScaleRulerInputCache,
|
|
|
...this.data,
|
|
|
centerScaleRulerAnchorMode: nextAnchorMode,
|
|
|
} as MapPageData
|