feat: 添加快捷动作功能,支持快速记录饮水量,更新相关配置和服务
This commit is contained in:
11
app.json
11
app.json
@@ -68,6 +68,17 @@
|
|||||||
"./assets/sounds/notification.wav"
|
"./assets/sounds/notification.wav"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"expo-quick-actions",
|
||||||
|
{
|
||||||
|
"androidIcons": {
|
||||||
|
"drink_water": "./assets/images/icons/IconGlass.png"
|
||||||
|
},
|
||||||
|
"iosIcons": {
|
||||||
|
"drink_water": "./assets/images/icons/IconGlass.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"experiments": {
|
"experiments": {
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ import 'react-native-reanimated';
|
|||||||
|
|
||||||
import PrivacyConsentModal from '@/components/PrivacyConsentModal';
|
import PrivacyConsentModal from '@/components/PrivacyConsentModal';
|
||||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||||
|
import { useQuickActions } from '@/hooks/useQuickActions';
|
||||||
import { clearAiCoachSessionCache } from '@/services/aiCoachSession';
|
import { clearAiCoachSessionCache } from '@/services/aiCoachSession';
|
||||||
import { backgroundTaskManager } from '@/services/backgroundTaskManager';
|
import { backgroundTaskManager } from '@/services/backgroundTaskManager';
|
||||||
import { notificationService } from '@/services/notifications';
|
import { notificationService } from '@/services/notifications';
|
||||||
|
import { setupQuickActions } from '@/services/quickActions';
|
||||||
import { store } from '@/store';
|
import { store } from '@/store';
|
||||||
import { rehydrateUser, setPrivacyAgreed } from '@/store/userSlice';
|
import { rehydrateUser, setPrivacyAgreed } from '@/store/userSlice';
|
||||||
import { MoodNotificationHelpers, NutritionNotificationHelpers } from '@/utils/notificationHelpers';
|
import { MoodNotificationHelpers, NutritionNotificationHelpers } from '@/utils/notificationHelpers';
|
||||||
@@ -26,6 +28,9 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
|||||||
const [showPrivacyModal, setShowPrivacyModal] = React.useState(false);
|
const [showPrivacyModal, setShowPrivacyModal] = React.useState(false);
|
||||||
const [userDataLoaded, setUserDataLoaded] = React.useState(false);
|
const [userDataLoaded, setUserDataLoaded] = React.useState(false);
|
||||||
|
|
||||||
|
// 初始化快捷动作处理
|
||||||
|
useQuickActions();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const loadUserData = async () => {
|
const loadUserData = async () => {
|
||||||
await dispatch(rehydrateUser());
|
await dispatch(rehydrateUser());
|
||||||
@@ -40,8 +45,12 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
|||||||
// 初始化后台任务管理器
|
// 初始化后台任务管理器
|
||||||
await backgroundTaskManager.initialize();
|
await backgroundTaskManager.initialize();
|
||||||
console.log('后台任务管理器初始化成功');
|
console.log('后台任务管理器初始化成功');
|
||||||
|
|
||||||
|
// 初始化快捷动作
|
||||||
|
await setupQuickActions();
|
||||||
|
console.log('快捷动作初始化成功');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('通知服务或后台任务管理器初始化失败:', error);
|
console.error('通知服务、后台任务管理器或快捷动作初始化失败:', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
76
hooks/useQuickActions.ts
Normal file
76
hooks/useQuickActions.ts
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import { useWaterData } from '@/hooks/useWaterData';
|
||||||
|
import { getInitialQuickAction } from '@/services/quickActions';
|
||||||
|
import { Toast } from '@/utils/toast.utils';
|
||||||
|
import * as Haptics from 'expo-haptics';
|
||||||
|
import * as QuickActions from 'expo-quick-actions';
|
||||||
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
export const useQuickActions = () => {
|
||||||
|
const { addWaterRecord } = useWaterData();
|
||||||
|
const subscriptionRef = useRef<any>(null);
|
||||||
|
|
||||||
|
// 处理快捷动作
|
||||||
|
const handleQuickAction = useCallback(async (action: any) => {
|
||||||
|
console.log('处理快捷动作:', action);
|
||||||
|
|
||||||
|
// 触发震动反馈
|
||||||
|
if (process.env.EXPO_OS === 'ios') {
|
||||||
|
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是饮水快捷动作
|
||||||
|
if (action.id?.startsWith('drink_water')) {
|
||||||
|
const amount = action.params?.amount || 250; // 默认250ml
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 添加饮水记录
|
||||||
|
const success = await addWaterRecord(amount);
|
||||||
|
if (success) {
|
||||||
|
Toast.success(`已记录饮水 ${amount}ml`);
|
||||||
|
} else {
|
||||||
|
Toast.error('添加饮水记录失败,请稍后重试');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('快捷饮水失败:', error);
|
||||||
|
Toast.error('添加饮水记录失败,请稍后重试');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [addWaterRecord]);
|
||||||
|
|
||||||
|
// 设置快捷动作监听器
|
||||||
|
useEffect(() => {
|
||||||
|
const setupListener = () => {
|
||||||
|
try {
|
||||||
|
// 先处理初始快捷动作(如果应用是通过快捷动作启动的)
|
||||||
|
const initialAction = getInitialQuickAction();
|
||||||
|
if (initialAction) {
|
||||||
|
console.log('检测到初始快捷动作:', initialAction);
|
||||||
|
handleQuickAction(initialAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置监听器处理后续的快捷动作
|
||||||
|
subscriptionRef.current = QuickActions.addListener(async (action) => {
|
||||||
|
await handleQuickAction(action);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('快捷动作监听器已设置');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('设置快捷动作监听器失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setupListener();
|
||||||
|
|
||||||
|
// 清理函数
|
||||||
|
return () => {
|
||||||
|
if (subscriptionRef.current) {
|
||||||
|
subscriptionRef.current.remove();
|
||||||
|
console.log('快捷动作监听器已清理');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [handleQuickAction]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleQuickAction,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -92,6 +92,8 @@ PODS:
|
|||||||
- ReactCommon/turbomodule/bridging
|
- ReactCommon/turbomodule/bridging
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- Yoga
|
- Yoga
|
||||||
|
- ExpoQuickActions (5.0.0):
|
||||||
|
- ExpoModulesCore
|
||||||
- ExpoSplashScreen (0.30.10):
|
- ExpoSplashScreen (0.30.10):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoSymbols (0.4.5):
|
- ExpoSymbols (0.4.5):
|
||||||
@@ -2011,6 +2013,7 @@ DEPENDENCIES:
|
|||||||
- ExpoLinearGradient (from `../node_modules/expo-linear-gradient/ios`)
|
- ExpoLinearGradient (from `../node_modules/expo-linear-gradient/ios`)
|
||||||
- ExpoLinking (from `../node_modules/expo-linking/ios`)
|
- ExpoLinking (from `../node_modules/expo-linking/ios`)
|
||||||
- ExpoModulesCore (from `../node_modules/expo-modules-core`)
|
- ExpoModulesCore (from `../node_modules/expo-modules-core`)
|
||||||
|
- ExpoQuickActions (from `../node_modules/expo-quick-actions/ios`)
|
||||||
- ExpoSplashScreen (from `../node_modules/expo-splash-screen/ios`)
|
- ExpoSplashScreen (from `../node_modules/expo-splash-screen/ios`)
|
||||||
- ExpoSymbols (from `../node_modules/expo-symbols/ios`)
|
- ExpoSymbols (from `../node_modules/expo-symbols/ios`)
|
||||||
- ExpoSystemUI (from `../node_modules/expo-system-ui/ios`)
|
- ExpoSystemUI (from `../node_modules/expo-system-ui/ios`)
|
||||||
@@ -2165,6 +2168,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: "../node_modules/expo-linking/ios"
|
:path: "../node_modules/expo-linking/ios"
|
||||||
ExpoModulesCore:
|
ExpoModulesCore:
|
||||||
:path: "../node_modules/expo-modules-core"
|
:path: "../node_modules/expo-modules-core"
|
||||||
|
ExpoQuickActions:
|
||||||
|
:path: "../node_modules/expo-quick-actions/ios"
|
||||||
ExpoSplashScreen:
|
ExpoSplashScreen:
|
||||||
:path: "../node_modules/expo-splash-screen/ios"
|
:path: "../node_modules/expo-splash-screen/ios"
|
||||||
ExpoSymbols:
|
ExpoSymbols:
|
||||||
@@ -2366,6 +2371,7 @@ SPEC CHECKSUMS:
|
|||||||
ExpoLinearGradient: 7734c8059972fcf691fb4330bcdf3390960a152d
|
ExpoLinearGradient: 7734c8059972fcf691fb4330bcdf3390960a152d
|
||||||
ExpoLinking: d5c183998ca6ada66ff45e407e0f965b398a8902
|
ExpoLinking: d5c183998ca6ada66ff45e407e0f965b398a8902
|
||||||
ExpoModulesCore: 272bc6c06ddd9c4bee2048acc57891cab3700627
|
ExpoModulesCore: 272bc6c06ddd9c4bee2048acc57891cab3700627
|
||||||
|
ExpoQuickActions: fdbda7f5874aed3dd2b1d891ec00ab3300dc7541
|
||||||
ExpoSplashScreen: 1c22c5d37647106e42d4ae1582bb6d0dda3b2385
|
ExpoSplashScreen: 1c22c5d37647106e42d4ae1582bb6d0dda3b2385
|
||||||
ExpoSymbols: c5612a90fb9179cdaebcd19bea9d8c69e5d3b859
|
ExpoSymbols: c5612a90fb9179cdaebcd19bea9d8c69e5d3b859
|
||||||
ExpoSystemUI: 433a971503b99020318518ed30a58204288bab2d
|
ExpoSystemUI: 433a971503b99020318518ed30a58204288bab2d
|
||||||
|
|||||||
@@ -89,5 +89,53 @@
|
|||||||
<string>Light</string>
|
<string>Light</string>
|
||||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
<false/>
|
<false/>
|
||||||
|
<key>UIApplicationShortcutItems</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationShortcutItemIconFile</key>
|
||||||
|
<string>IconGlass</string>
|
||||||
|
<key>UIApplicationShortcutItemTitle</key>
|
||||||
|
<string>喝水</string>
|
||||||
|
<key>UIApplicationShortcutItemSubtitle</key>
|
||||||
|
<string>快速记录饮水</string>
|
||||||
|
<key>UIApplicationShortcutItemType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER).drink_water</string>
|
||||||
|
<key>UIApplicationShortcutItemUserInfo</key>
|
||||||
|
<dict>
|
||||||
|
<key>amount</key>
|
||||||
|
<integer>250</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationShortcutItemIconFile</key>
|
||||||
|
<string>IconGlass</string>
|
||||||
|
<key>UIApplicationShortcutItemTitle</key>
|
||||||
|
<string>喝水 100ml</string>
|
||||||
|
<key>UIApplicationShortcutItemSubtitle</key>
|
||||||
|
<string>快速记录饮水</string>
|
||||||
|
<key>UIApplicationShortcutItemType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER).drink_water_100</string>
|
||||||
|
<key>UIApplicationShortcutItemUserInfo</key>
|
||||||
|
<dict>
|
||||||
|
<key>amount</key>
|
||||||
|
<integer>100</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationShortcutItemIconFile</key>
|
||||||
|
<string>IconGlass</string>
|
||||||
|
<key>UIApplicationShortcutItemTitle</key>
|
||||||
|
<string>喝水 200ml</string>
|
||||||
|
<key>UIApplicationShortcutItemSubtitle</key>
|
||||||
|
<string>快速记录饮水</string>
|
||||||
|
<key>UIApplicationShortcutItemType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER).drink_water_200</string>
|
||||||
|
<key>UIApplicationShortcutItemUserInfo</key>
|
||||||
|
<dict>
|
||||||
|
<key>amount</key>
|
||||||
|
<integer>200</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
116
package-lock.json
generated
116
package-lock.json
generated
@@ -33,6 +33,7 @@
|
|||||||
"expo-linear-gradient": "^14.1.5",
|
"expo-linear-gradient": "^14.1.5",
|
||||||
"expo-linking": "~7.1.7",
|
"expo-linking": "~7.1.7",
|
||||||
"expo-notifications": "~0.31.4",
|
"expo-notifications": "~0.31.4",
|
||||||
|
"expo-quick-actions": "^5.0.0",
|
||||||
"expo-router": "~5.1.5",
|
"expo-router": "~5.1.5",
|
||||||
"expo-splash-screen": "~0.30.10",
|
"expo-splash-screen": "~0.30.10",
|
||||||
"expo-status-bar": "~2.2.3",
|
"expo-status-bar": "~2.2.3",
|
||||||
@@ -3919,7 +3920,6 @@
|
|||||||
"version": "7.0.15",
|
"version": "7.0.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
|
||||||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/json5": {
|
"node_modules/@types/json5": {
|
||||||
@@ -4651,6 +4651,42 @@
|
|||||||
"url": "https://github.com/sponsors/epoberezkin"
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ajv-formats": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/ajv-formats/-/ajv-formats-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ajv": "^8.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"ajv": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ajv-formats/node_modules/ajv": {
|
||||||
|
"version": "8.17.1",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/ajv/-/ajv-8.17.1.tgz",
|
||||||
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"fast-uri": "^3.0.1",
|
||||||
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
"require-from-string": "^2.0.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ajv-formats/node_modules/json-schema-traverse": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||||
|
},
|
||||||
"node_modules/anser": {
|
"node_modules/anser": {
|
||||||
"version": "1.4.10",
|
"version": "1.4.10",
|
||||||
"resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz",
|
"resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz",
|
||||||
@@ -7286,6 +7322,20 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/expo-quick-actions": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/expo-quick-actions/-/expo-quick-actions-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-NSsDhfbal11gXsHkJbvYVw7x0QUCKrEth2kBBKZUv03dX4J7ZPADSV89LyEpOVYXCkrw6LuanlEtKavg/BFaRA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@expo/image-utils": "~0.7.4",
|
||||||
|
"schema-utils": "^4.2.0",
|
||||||
|
"sf-symbols-typescript": "^2.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"expo": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/expo-router": {
|
"node_modules/expo-router": {
|
||||||
"version": "5.1.5",
|
"version": "5.1.5",
|
||||||
"resolved": "https://mirrors.tencent.com/npm/expo-router/-/expo-router-5.1.5.tgz",
|
"resolved": "https://mirrors.tencent.com/npm/expo-router/-/expo-router-5.1.5.tgz",
|
||||||
@@ -7470,6 +7520,21 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/fast-uri": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/fast-uri/-/fast-uri-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fastify"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/fastify"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/fast-xml-parser": {
|
"node_modules/fast-xml-parser": {
|
||||||
"version": "4.5.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://mirrors.tencent.com/npm/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz",
|
"resolved": "https://mirrors.tencent.com/npm/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz",
|
||||||
@@ -12376,6 +12441,55 @@
|
|||||||
"integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
|
"integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/schema-utils": {
|
||||||
|
"version": "4.3.2",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/schema-utils/-/schema-utils-4.3.2.tgz",
|
||||||
|
"integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/json-schema": "^7.0.9",
|
||||||
|
"ajv": "^8.9.0",
|
||||||
|
"ajv-formats": "^2.1.1",
|
||||||
|
"ajv-keywords": "^5.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.13.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/webpack"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/schema-utils/node_modules/ajv": {
|
||||||
|
"version": "8.17.1",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/ajv/-/ajv-8.17.1.tgz",
|
||||||
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"fast-uri": "^3.0.1",
|
||||||
|
"json-schema-traverse": "^1.0.0",
|
||||||
|
"require-from-string": "^2.0.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/epoberezkin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/schema-utils/node_modules/ajv-keywords": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
|
||||||
|
"dependencies": {
|
||||||
|
"fast-deep-equal": "^3.1.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"ajv": "^8.8.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/schema-utils/node_modules/json-schema-traverse": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://mirrors.tencent.com/npm/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
|
||||||
|
},
|
||||||
"node_modules/semver": {
|
"node_modules/semver": {
|
||||||
"version": "6.3.1",
|
"version": "6.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
"expo-linear-gradient": "^14.1.5",
|
"expo-linear-gradient": "^14.1.5",
|
||||||
"expo-linking": "~7.1.7",
|
"expo-linking": "~7.1.7",
|
||||||
"expo-notifications": "~0.31.4",
|
"expo-notifications": "~0.31.4",
|
||||||
|
"expo-quick-actions": "^5.0.0",
|
||||||
"expo-router": "~5.1.5",
|
"expo-router": "~5.1.5",
|
||||||
"expo-splash-screen": "~0.30.10",
|
"expo-splash-screen": "~0.30.10",
|
||||||
"expo-status-bar": "~2.2.3",
|
"expo-status-bar": "~2.2.3",
|
||||||
|
|||||||
116
services/quickActions.ts
Normal file
116
services/quickActions.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import { getQuickWaterAmount } from '@/utils/userPreferences';
|
||||||
|
import * as QuickActions from 'expo-quick-actions';
|
||||||
|
import { Platform } from 'react-native';
|
||||||
|
|
||||||
|
// 快捷动作类型定义
|
||||||
|
export interface QuickActionItem {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
subtitle?: string;
|
||||||
|
icon?: string;
|
||||||
|
params?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 饮水快捷动作配置
|
||||||
|
export const QUICK_ACTIONS = {
|
||||||
|
DRINK_WATER_100: {
|
||||||
|
id: 'drink_water_100',
|
||||||
|
title: '喝水 100ml',
|
||||||
|
subtitle: '快速记录饮水',
|
||||||
|
icon: Platform.OS === 'ios' ? 'drink_water' : 'drink_water',
|
||||||
|
params: { amount: 100 }
|
||||||
|
},
|
||||||
|
DRINK_WATER_200: {
|
||||||
|
id: 'drink_water_200',
|
||||||
|
title: '喝水 200ml',
|
||||||
|
subtitle: '快速记录饮水',
|
||||||
|
icon: Platform.OS === 'ios' ? 'drink_water' : 'drink_water',
|
||||||
|
params: { amount: 200 }
|
||||||
|
},
|
||||||
|
DRINK_WATER_250: {
|
||||||
|
id: 'drink_water_250',
|
||||||
|
title: '喝水 250ml',
|
||||||
|
subtitle: '快速记录饮水',
|
||||||
|
icon: Platform.OS === 'ios' ? 'drink_water' : 'drink_water',
|
||||||
|
params: { amount: 250 }
|
||||||
|
},
|
||||||
|
DRINK_WATER_CUSTOM: {
|
||||||
|
id: 'drink_water_custom',
|
||||||
|
title: '喝水',
|
||||||
|
subtitle: '自定义饮水量',
|
||||||
|
icon: Platform.OS === 'ios' ? 'drink_water' : 'drink_water',
|
||||||
|
params: { custom: true }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置快捷动作
|
||||||
|
export const setupQuickActions = async () => {
|
||||||
|
try {
|
||||||
|
// 获取用户设置的快速饮水量
|
||||||
|
const quickAmount = await getQuickWaterAmount();
|
||||||
|
console.log('设置快捷动作,快速饮水量:', quickAmount);
|
||||||
|
|
||||||
|
// 创建快捷动作列表
|
||||||
|
const actions: QuickActionItem[] = [
|
||||||
|
// 使用用户设置的快速饮水量
|
||||||
|
{
|
||||||
|
...QUICK_ACTIONS.DRINK_WATER_CUSTOM,
|
||||||
|
title: `喝水 ${quickAmount}ml`,
|
||||||
|
subtitle: '快速记录饮水',
|
||||||
|
params: { amount: quickAmount }
|
||||||
|
},
|
||||||
|
// 固定选项
|
||||||
|
QUICK_ACTIONS.DRINK_WATER_100,
|
||||||
|
QUICK_ACTIONS.DRINK_WATER_200,
|
||||||
|
QUICK_ACTIONS.DRINK_WATER_250
|
||||||
|
];
|
||||||
|
|
||||||
|
// 设置快捷动作
|
||||||
|
await QuickActions.setItems(actions);
|
||||||
|
console.log('快捷动作设置成功');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('设置快捷动作失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清除所有快捷动作
|
||||||
|
export const clearQuickActions = async () => {
|
||||||
|
try {
|
||||||
|
await QuickActions.setItems([]);
|
||||||
|
console.log('快捷动作已清除');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('清除快捷动作失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取初始快捷动作(如果应用是通过快捷动作启动的)
|
||||||
|
export const getInitialQuickAction = () => {
|
||||||
|
try {
|
||||||
|
return QuickActions.initial;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取初始快捷动作失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加快捷动作事件监听器
|
||||||
|
export const addQuickActionListener = (callback: (action: QuickActionItem) => void) => {
|
||||||
|
const subscription = QuickActions.addListener(callback);
|
||||||
|
return subscription;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除快捷动作事件监听器
|
||||||
|
export const removeQuickActionListener = (subscription: any) => {
|
||||||
|
if (subscription) {
|
||||||
|
subscription.remove();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 检查快捷动作是否可用
|
||||||
|
export const isQuickActionsAvailable = async () => {
|
||||||
|
try {
|
||||||
|
return await QuickActions.isSupported();
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user