071faa482c
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口 完成项目 TypeScript/Prettier 与 Rust 全量格式化 修复 Pingora expected executable 门禁的空白敏感误报 同步开发运维文档与 AGC skill pack 格式化忽略规则
54 lines
1.5 KiB
TypeScript
54 lines
1.5 KiB
TypeScript
import * as Haptics from 'expo-haptics';
|
|
|
|
import {
|
|
type HapticsImpactPayload,
|
|
type HostBridgeError,
|
|
type HostBridgeHapticsImpactStyle,
|
|
type HostBridgeRequest,
|
|
normalizeHostBridgeHapticsImpactStyle,
|
|
} from '../../../../packages/shared/src/contracts/hostBridge';
|
|
import { invalidRequest, ok } from './protocol';
|
|
|
|
function toExpoImpactStyle(style: HostBridgeHapticsImpactStyle) {
|
|
return style === 'heavy'
|
|
? Haptics.ImpactFeedbackStyle.Heavy
|
|
: style === 'medium'
|
|
? Haptics.ImpactFeedbackStyle.Medium
|
|
: Haptics.ImpactFeedbackStyle.Light;
|
|
}
|
|
|
|
function logMobileHapticsFailure(label: string, _error: unknown) {
|
|
console.warn(`mobile haptics failed for ${label}`);
|
|
}
|
|
|
|
export async function runMobileHapticsImpact(rawStyle: unknown) {
|
|
const style = normalizeHostBridgeHapticsImpactStyle(rawStyle);
|
|
if (!style) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
await Haptics.impactAsync(toExpoImpactStyle(style));
|
|
} catch (error) {
|
|
logMobileHapticsFailure('impact.dispatch', error);
|
|
throw {
|
|
code: 'host_error',
|
|
message: 'haptics impact unavailable',
|
|
} satisfies HostBridgeError;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
export async function runMobileHostBridgeHapticsImpact(
|
|
request: HostBridgeRequest,
|
|
) {
|
|
const style = (request.payload as HapticsImpactPayload | undefined)?.style;
|
|
if (!(await runMobileHapticsImpact(style))) {
|
|
throw invalidRequest(
|
|
'haptics impact style must be light, medium, or heavy',
|
|
);
|
|
}
|
|
|
|
return ok(request, true);
|
|
}
|