feat(app): add version check system and enhance internationalization support

Add comprehensive app update checking functionality with:
- New VersionCheckContext for managing update detection and notifications
- VersionUpdateModal UI component for presenting update information
- Version service API integration with platform-specific update URLs
- Version check menu item in personal settings with manual/automatic checking

Enhance internationalization across workout features:
- Complete workout type translations for English and Chinese
- Localized workout detail modal with proper date/time formatting
- Locale-aware date formatting in fitness rings detail
- Workout notification improvements with deep linking to specific workout details

Improve UI/UX with better chart rendering, sizing fixes, and enhanced navigation flow. Update app version to 1.1.3 and include app version in API headers for better tracking.
This commit is contained in:
2025-11-29 20:47:16 +08:00
parent 83b77615cf
commit a309123b35
19 changed files with 1132 additions and 159 deletions

View File

@@ -338,6 +338,9 @@ export const fitnessRingsDetail = {
saturday: 'Sat',
sunday: 'Sun',
},
dateFormats: {
header: 'MMM D, YYYY',
},
cards: {
activeCalories: {
title: 'Active Calories',
@@ -474,6 +477,159 @@ export const basalMetabolismDetail = {
},
};
export const workoutTypes = {
americanfootball: 'American Football',
archery: 'Archery',
australianfootball: 'Australian Football',
badminton: 'Badminton',
baseball: 'Baseball',
basketball: 'Basketball',
bowling: 'Bowling',
boxing: 'Boxing',
climbing: 'Climbing',
cricket: 'Cricket',
crosstraining: 'Cross Training',
curling: 'Curling',
cycling: 'Cycling',
dance: 'Dance',
danceinspiredtraining: 'Dance Inspired Training',
elliptical: 'Elliptical',
equestriansports: 'Equestrian Sports',
fencing: 'Fencing',
fishing: 'Fishing',
functionalstrengthtraining: 'Functional Strength Training',
golf: 'Golf',
gymnastics: 'Gymnastics',
handball: 'Handball',
hiking: 'Hiking',
hockey: 'Hockey',
hunting: 'Hunting',
lacrosse: 'Lacrosse',
martialarts: 'Martial Arts',
mindandbody: 'Mind and Body',
mixedmetaboliccardiotraining: 'Mixed Metabolic Cardio Training',
paddlesports: 'Paddle Sports',
play: 'Play',
preparationandrecovery: 'Preparation & Recovery',
racquetball: 'Racquetball',
rowing: 'Rowing',
rugby: 'Rugby',
running: 'Running',
sailing: 'Sailing',
skatingsports: 'Skating Sports',
snowsports: 'Snow Sports',
soccer: 'Soccer',
softball: 'Softball',
squash: 'Squash',
stairclimbing: 'Stair Climbing',
surfingsports: 'Surfing Sports',
swimming: 'Swimming',
tabletennis: 'Table Tennis',
tennis: 'Tennis',
trackandfield: 'Track and Field',
traditionalstrengthtraining: 'Traditional Strength Training',
volleyball: 'Volleyball',
walking: 'Walking',
waterfitness: 'Water Fitness',
waterpolo: 'Water Polo',
watersports: 'Water Sports',
wrestling: 'Wrestling',
yoga: 'Yoga',
barre: 'Barre',
coretraining: 'Core Training',
crosscountryskiing: 'Cross-Country Skiing',
downhillskiing: 'Downhill Skiing',
flexibility: 'Flexibility',
highintensityintervaltraining: 'High-Intensity Interval Training',
jumprope: 'Jump Rope',
kickboxing: 'Kickboxing',
pilates: 'Pilates',
snowboarding: 'Snowboarding',
stairs: 'Stairs',
steptraining: 'Step Training',
wheelchairwalkpace: 'Wheelchair Walk Pace',
wheelchairrunpace: 'Wheelchair Run Pace',
taichi: 'Tai Chi',
mixedcardio: 'Mixed Cardio',
handcycling: 'Hand Cycling',
discsports: 'Disc Sports',
fitnessgaming: 'Fitness Gaming',
cardiodance: 'Cardio Dance',
socialdance: 'Social Dance',
pickleball: 'Pickleball',
cooldown: 'Cooldown',
swimbikerun: 'Swim Bike Run',
transition: 'Transition',
underwaterdiving: 'Underwater Diving',
other: 'Other',
};
export const workoutDetail = {
loading: 'Loading workout details...',
retry: 'Retry',
errors: {
loadFailed: 'Failed to load workout details',
noHeartRateData: 'No heart rate data available',
noZoneStats: 'No heart rate zone data',
},
metrics: {
duration: 'Duration',
calories: 'Calories',
caloriesUnit: 'kcal',
intensity: 'Intensity',
averageHeartRate: 'Average Heart Rate',
heartRateUnit: 'bpm',
},
sections: {
heartRateRange: 'Heart Rate Range',
averageHeartRate: 'Average',
maximumHeartRate: 'Maximum',
minimumHeartRate: 'Minimum',
heartRateUnit: 'bpm',
heartRateZones: 'Heart Rate Zones',
},
chart: {
unavailable: 'Chart unavailable',
noData: 'No heart rate chart data yet',
},
intensityInfo: {
title: 'About workout intensity (METs)',
description1: 'METs (metabolic equivalent) reflect energy cost; resting equals 1 MET.',
description2: '3-6 METs is moderate intensity, above 6 METs is high intensity.',
description3: 'Higher values mean more energy burned per minute—adjust to your fitness level.',
description4: 'Warm up and cool down before and after sustained high-intensity sessions.',
formula: {
title: 'Formula',
value: 'METs = Exercise VO₂ ÷ Resting VO₂',
},
legend: {
low: '2-3 METs',
lowLabel: 'Low intensity',
medium: '3-6 METs',
mediumLabel: 'Moderate',
high: '>6 METs',
highLabel: 'High intensity',
},
},
zones: {
summary: '{{minutes}} min · {{range}}',
labels: {
warmup: 'Warm-up',
fatburn: 'Fat burn',
aerobic: 'Aerobic',
anaerobic: 'Anaerobic',
max: 'Max effort',
},
ranges: {
warmup: '<100 bpm',
fatburn: '100-119 bpm',
aerobic: '120-149 bpm',
anaerobic: '150-169 bpm',
max: '≥170 bpm',
},
},
};
export const workoutHistory = {
title: 'Workout Summary',
loading: 'Loading workout records...',
@@ -504,4 +660,4 @@ export const workoutHistory = {
subtitle: 'Complete a workout to view detailed history here',
},
monthOccurrence: 'This is your {{index}} {{activity}} in {{month}}.',
};
};

View File

@@ -37,6 +37,25 @@ export const personal = {
medicalSources: 'Medical Advice Sources',
customization: 'Customization',
},
versionCheck: {
sectionTitle: 'Updates',
menuTitle: 'Check for updates',
checking: 'Checking for updates...',
upToDate: 'You are on the latest version',
updateBadge: 'v{{version}} available',
failed: 'Update check failed, please try again later',
updateFound: 'New version v{{version}}',
modalTitle: 'Update available',
modalTag: 'New',
currentVersion: 'Current',
latestVersion: 'Latest',
releaseNotesTitle: "What's new",
fallbackNotes: 'Performance improvements and fixes to keep things smooth.',
later: 'Remind me later',
updateNow: 'Update now',
missingUrl: 'Store link is not ready yet',
openStoreFailed: 'Could not open the store, please try again',
},
menu: {
notificationSettings: 'Notification settings',
developerOptions: 'Developer options',
@@ -405,4 +424,4 @@ export const notificationSettings = {
body: 'You will receive mood record reminders in the evening',
},
},
};
};

View File

@@ -338,6 +338,9 @@ export const fitnessRingsDetail = {
saturday: '周六',
sunday: '周日',
},
dateFormats: {
header: 'YYYY年MM月DD日',
},
cards: {
activeCalories: {
title: '活动热量',
@@ -474,6 +477,159 @@ export const basalMetabolismDetail = {
},
};
export const workoutTypes = {
americanfootball: '美式橄榄球',
archery: '射箭',
australianfootball: '澳式橄榄球',
badminton: '羽毛球',
baseball: '棒球',
basketball: '篮球',
bowling: '保龄球',
boxing: '拳击',
climbing: '攀岩',
cricket: '板球',
crosstraining: '交叉训练',
curling: '冰壶',
cycling: '骑行',
dance: '舞蹈',
danceinspiredtraining: '舞蹈灵感训练',
elliptical: '椭圆机',
equestriansports: '马术',
fencing: '击剑',
fishing: '钓鱼',
functionalstrengthtraining: '功能性力量训练',
golf: '高尔夫',
gymnastics: '体操',
handball: '手球',
hiking: '徒步',
hockey: '曲棍球',
hunting: '打猎',
lacrosse: '长曲棍球',
martialarts: '武术',
mindandbody: '身心训练',
mixedmetaboliccardiotraining: '混合代谢有氧训练',
paddlesports: '划桨运动',
play: '玩乐活动',
preparationandrecovery: '热身与恢复',
racquetball: '回力球',
rowing: '划船',
rugby: '橄榄球',
running: '跑步',
sailing: '帆船',
skatingsports: '滑冰运动',
snowsports: '冰雪运动',
soccer: '足球',
softball: '垒球',
squash: '壁球',
stairclimbing: '爬楼梯',
surfingsports: '冲浪',
swimming: '游泳',
tabletennis: '乒乓球',
tennis: '网球',
trackandfield: '田径',
traditionalstrengthtraining: '力量训练',
volleyball: '排球',
walking: '步行',
waterfitness: '水中健身',
waterpolo: '水球',
watersports: '水上运动',
wrestling: '摔跤',
yoga: '瑜伽',
barre: '芭蕾塑形',
coretraining: '核心训练',
crosscountryskiing: '越野滑雪',
downhillskiing: '高山滑雪',
flexibility: '柔韧训练',
highintensityintervaltraining: '高强度间歇训练',
jumprope: '跳绳',
kickboxing: '踢拳',
pilates: '普拉提',
snowboarding: '单板滑雪',
stairs: '楼梯',
steptraining: '踏步训练',
wheelchairwalkpace: '轮椅慢速',
wheelchairrunpace: '轮椅快速',
taichi: '太极',
mixedcardio: '混合有氧',
handcycling: '手摇车',
discsports: '飞盘',
fitnessgaming: '健身游戏',
cardiodance: '有氧舞蹈',
socialdance: '社交舞',
pickleball: '匹克球',
cooldown: '整理放松',
swimbikerun: '游泳+骑行+跑步',
transition: '过渡',
underwaterdiving: '潜水',
other: '其他',
};
export const workoutDetail = {
loading: '正在加载锻炼详情...',
retry: '重试',
errors: {
loadFailed: '加载锻炼详情失败',
noHeartRateData: '暂无心率数据',
noZoneStats: '暂无心率分区数据',
},
metrics: {
duration: '时长',
calories: '消耗',
caloriesUnit: '千卡',
intensity: '强度',
averageHeartRate: '平均心率',
heartRateUnit: '次/分',
},
sections: {
heartRateRange: '心率范围',
averageHeartRate: '平均',
maximumHeartRate: '最高',
minimumHeartRate: '最低',
heartRateUnit: '次/分',
heartRateZones: '心率区间',
},
chart: {
unavailable: '暂无法展示图表',
noData: '暂无心率曲线数据',
},
intensityInfo: {
title: '关于运动强度METs',
description1: 'METs代谢当量反映运动能量消耗静息时为 1 MET。',
description2: '3-6 METs 属于中等强度,高于 6 METs 为高强度。',
description3: '数值越高每分钟消耗越多,请结合个人体能选择强度。',
description4: '长时间高强度训练前后,请确保充分热身与放松。',
formula: {
title: '计算方式',
value: 'METs = 运动摄氧量 ÷ 静息摄氧量',
},
legend: {
low: '2-3 METs',
lowLabel: '低强度',
medium: '3-6 METs',
mediumLabel: '中等强度',
high: '>6 METs',
highLabel: '高强度',
},
},
zones: {
summary: '{{minutes}} 分钟 · {{range}}',
labels: {
warmup: '热身放松',
fatburn: '燃脂',
aerobic: '有氧运动',
anaerobic: '无氧冲刺',
max: '身体极限',
},
ranges: {
warmup: '<100次/分',
fatburn: '100-119次/分',
aerobic: '120-149次/分',
anaerobic: '150-169次/分',
max: '≥170次/分',
},
},
};
export const workoutHistory = {
title: '锻炼总结',
loading: '正在加载锻炼记录...',
@@ -504,4 +660,4 @@ export const workoutHistory = {
subtitle: '完成一次锻炼后即可在此查看详细历史',
},
monthOccurrence: '这是你{{month}}的第 {{index}} 次{{activity}}。',
};
};

View File

@@ -37,6 +37,25 @@ export const personal = {
medicalSources: '医学建议来源',
customization: '个性化',
},
versionCheck: {
sectionTitle: '版本与更新',
menuTitle: '检查更新',
checking: '正在检查更新...',
upToDate: '当前已是最新版本',
updateBadge: 'v{{version}} 可更新',
failed: '检查更新失败,请稍后再试',
updateFound: '发现新版本 v{{version}}',
modalTitle: '发现新版本',
modalTag: 'New',
currentVersion: '当前',
latestVersion: '最新',
releaseNotesTitle: '本次更新',
fallbackNotes: '体验优化与问题修复,保持更新获得更好体验。',
later: '稍后提醒',
updateNow: '立即更新',
missingUrl: '暂未获取到商店地址',
openStoreFailed: '跳转应用商店失败,请稍后再试',
},
menu: {
notificationSettings: '通知设置',
developerOptions: '开发者选项',
@@ -405,4 +424,4 @@ export const notificationSettings = {
body: '您将在晚间收到心情记录提醒',
},
},
};
};