- 新增iOS原生Toast模块(NativeToastManager),提供毛玻璃风格的Toast展示 - 重构ToastContext为原生模块调用,添加错误边界和回退机制 - 优化会员购买流程的错误处理,使用RevenueCat标准错误码 - 调整购买按钮高度和恢复购买按钮字体大小,改善UI体验 - 移除不必要的延迟和注释代码,提升代码质量
123 lines
3.2 KiB
TypeScript
123 lines
3.2 KiB
TypeScript
/**
|
||
* Global toast helper backed by native UI.
|
||
*
|
||
* Usage:
|
||
* import { Toast } from '@/utils/toast.utils';
|
||
*
|
||
* Toast.success('操作成功!');
|
||
* Toast.error('操作失败!');
|
||
* Toast.warning('注意!');
|
||
*/
|
||
|
||
import { NativeModules, Platform, ToastAndroid } from 'react-native';
|
||
|
||
export type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info';
|
||
|
||
export interface ToastConfig {
|
||
message?: string;
|
||
text1?: string;
|
||
duration?: number;
|
||
type?: ToastType;
|
||
backgroundColor?: string;
|
||
textColor?: string;
|
||
icon?: string;
|
||
}
|
||
|
||
type NativeToastModule = {
|
||
show: (options: {
|
||
message?: string;
|
||
text1?: string;
|
||
duration?: number;
|
||
type?: ToastType;
|
||
backgroundColor?: string;
|
||
textColor?: string;
|
||
icon?: string;
|
||
}) => void;
|
||
};
|
||
|
||
const DEFAULT_DURATION = 2000;
|
||
const MIN_DURATION = 1000;
|
||
const MAX_DURATION = 10000;
|
||
|
||
// 增强类型安全性:添加运行时检查确保模块存在且具有预期的方法
|
||
const nativeToast = NativeModules.NativeToastManager &&
|
||
typeof NativeModules.NativeToastManager.show === 'function'
|
||
? NativeModules.NativeToastManager as NativeToastModule
|
||
: undefined;
|
||
|
||
const clampDuration = (duration?: number) => {
|
||
const value = typeof duration === 'number' ? duration : DEFAULT_DURATION;
|
||
return Math.min(Math.max(value, MIN_DURATION), MAX_DURATION);
|
||
};
|
||
|
||
const resolveMessage = (config: ToastConfig) => {
|
||
const raw = (config.message ?? config.text1 ?? '').toString();
|
||
return raw.trim();
|
||
};
|
||
|
||
const showOnAndroid = (message: string, duration: number) => {
|
||
const toastDuration = duration >= 3000 ? ToastAndroid.LONG : ToastAndroid.SHORT;
|
||
ToastAndroid.showWithGravity(message, toastDuration, ToastAndroid.CENTER);
|
||
};
|
||
|
||
const showNative = (config: ToastConfig) => {
|
||
const message = resolveMessage(config);
|
||
|
||
if (!message) {
|
||
console.warn('Toast invoked without message content');
|
||
return;
|
||
}
|
||
|
||
const duration = clampDuration(config.duration);
|
||
const type = config.type ?? 'default';
|
||
|
||
if (Platform.OS === 'android') {
|
||
showOnAndroid(message, duration);
|
||
return;
|
||
}
|
||
|
||
if (nativeToast?.show) {
|
||
nativeToast.show({
|
||
...config,
|
||
message,
|
||
duration,
|
||
type,
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 为不支持的平台提供更明显的用户反馈
|
||
if (Platform.OS === 'web') {
|
||
// 在 Web 环境下使用 console.warn 并尝试使用浏览器原生 alert
|
||
console.warn(`Toast: ${message}`);
|
||
try {
|
||
// 仅在重要消息时使用 alert,避免过度打扰用户
|
||
if (config.type === 'error' || config.type === 'warning') {
|
||
alert(message);
|
||
}
|
||
} catch (e) {
|
||
// 忽略 alert 错误
|
||
}
|
||
} else {
|
||
console.log(`Toast: ${message}`);
|
||
}
|
||
};
|
||
|
||
export const Toast = {
|
||
show: (config: ToastConfig) => {
|
||
showNative(config);
|
||
},
|
||
success: (message: string, duration?: number) => {
|
||
showNative({ message, duration, type: 'success' });
|
||
},
|
||
error: (message: string, duration?: number) => {
|
||
showNative({ message, duration, type: 'error' });
|
||
},
|
||
warning: (message: string, duration?: number) => {
|
||
showNative({ message, duration, type: 'warning' });
|
||
},
|
||
info: (message: string, duration?: number) => {
|
||
showNative({ message, duration, type: 'info' });
|
||
},
|
||
};
|