1111
This commit is contained in:
parent
f7d44c9a34
commit
98cdfe7fb6
|
|
@ -518,51 +518,101 @@ class AppUpgradeSimple {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 使用 Overlay 显示 Toast(不依赖 Scaffold)
|
||||||
|
void _showOverlayToast(BuildContext context, String message, UpgradeConfig config) {
|
||||||
|
if (!context.mounted) {
|
||||||
|
debugPrint('Toast消息(context已卸载): $message');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final overlay = Overlay.of(context);
|
||||||
|
|
||||||
|
// 创建 OverlayEntry
|
||||||
|
final overlayEntry = OverlayEntry(
|
||||||
|
builder: (context) => _ToastWidget(message: message),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 插入到 Overlay
|
||||||
|
overlay.insert(overlayEntry);
|
||||||
|
|
||||||
|
// 2秒后自动移除
|
||||||
|
Future.delayed(const Duration(seconds: 2), () {
|
||||||
|
try {
|
||||||
|
overlayEntry.remove();
|
||||||
|
} catch (e) {
|
||||||
|
// 忽略移除错误
|
||||||
|
if (config.enableDebugLog) {
|
||||||
|
debugPrint('移除Toast失败: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('显示Toast失败: $e');
|
||||||
|
debugPrint('Toast消息: $message');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 尝试使用 ScaffoldMessenger 显示 SnackBar(如果可用)
|
||||||
|
void _tryShowSnackBar(BuildContext context, String message, UpgradeConfig config) {
|
||||||
|
if (!context.mounted) {
|
||||||
|
_showOverlayToast(context, message, config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试获取 ScaffoldMessenger
|
||||||
|
final scaffoldMessenger = ScaffoldMessenger.maybeOf(context);
|
||||||
|
if (scaffoldMessenger == null) {
|
||||||
|
// 如果没有 ScaffoldMessenger,使用 Overlay Toast
|
||||||
|
_showOverlayToast(context, message, config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试使用根 Navigator 的 context(更安全)
|
||||||
|
BuildContext? rootContext;
|
||||||
|
try {
|
||||||
|
final navigator = Navigator.maybeOf(context, rootNavigator: true);
|
||||||
|
if (navigator != null) {
|
||||||
|
rootContext = navigator.context;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 忽略错误,继续使用原 context
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先使用根 context 的 ScaffoldMessenger
|
||||||
|
final messenger =
|
||||||
|
rootContext != null && rootContext.mounted ? ScaffoldMessenger.maybeOf(rootContext) : scaffoldMessenger;
|
||||||
|
|
||||||
|
if (messenger == null) {
|
||||||
|
_showOverlayToast(context, message, config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试显示 SnackBar,如果失败则使用 Overlay Toast
|
||||||
|
try {
|
||||||
|
messenger.showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(message),
|
||||||
|
duration: Duration(seconds: 2),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// 如果 SnackBar 失败,使用 Overlay Toast
|
||||||
|
if (config.enableDebugLog) {
|
||||||
|
debugPrint('SnackBar显示失败,使用Overlay Toast: $e');
|
||||||
|
}
|
||||||
|
_showOverlayToast(context, message, config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 显示Toast提示
|
/// 显示Toast提示
|
||||||
void _showToast(String message, BuildContext context, [UpgradeConfig? config]) {
|
void _showToast(String message, BuildContext context, [UpgradeConfig? config]) {
|
||||||
final effectiveConfig = config ?? _config;
|
final effectiveConfig = config ?? _config;
|
||||||
if (effectiveConfig.customToast != null) {
|
if (effectiveConfig.customToast != null) {
|
||||||
effectiveConfig.customToast!(message);
|
effectiveConfig.customToast!(message);
|
||||||
} else {
|
} else {
|
||||||
// 检查 context 是否有效
|
// 优先尝试使用 SnackBar,如果失败则使用 Overlay Toast
|
||||||
if (!context.mounted) {
|
_tryShowSnackBar(context, message, effectiveConfig);
|
||||||
debugPrint('Toast消息(context已卸载): $message');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否有 Scaffold 在 widget 树中
|
|
||||||
final scaffold = Scaffold.maybeOf(context);
|
|
||||||
if (scaffold == null) {
|
|
||||||
// 如果没有 Scaffold,使用 debugPrint 作为后备方案
|
|
||||||
debugPrint('Toast消息(无Scaffold): $message');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用 maybeOf 安全地获取 ScaffoldMessenger
|
|
||||||
final scaffoldMessenger = ScaffoldMessenger.maybeOf(context);
|
|
||||||
if (scaffoldMessenger == null) {
|
|
||||||
// 如果没有 ScaffoldMessenger,使用 debugPrint 作为后备方案
|
|
||||||
debugPrint('Toast消息(无ScaffoldMessenger): $message');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 即使有 Scaffold 和 ScaffoldMessenger,也可能出现其他问题
|
|
||||||
// 使用 try-catch 捕获所有可能的错误
|
|
||||||
try {
|
|
||||||
scaffoldMessenger.showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(message),
|
|
||||||
duration: Duration(seconds: 2),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
// 捕获所有错误,包括断言错误
|
|
||||||
// 在调试模式下,断言错误可能仍然会显示,但不会导致应用崩溃
|
|
||||||
debugPrint('显示Toast失败(已使用后备方案): $message');
|
|
||||||
if (effectiveConfig.enableDebugLog) {
|
|
||||||
debugPrint('错误详情: $e');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2053,3 +2103,68 @@ class _ForceUpgradeDialogState extends State<_ForceUpgradeDialog> with _UpgradeD
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 使用 Overlay 显示的 Toast Widget(不依赖 Scaffold)
|
||||||
|
class _ToastWidget extends StatelessWidget {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const _ToastWidget({required this.message});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Positioned(
|
||||||
|
top: MediaQuery.of(context).padding.top + 16,
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: SafeArea(
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: TweenAnimationBuilder<double>(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
tween: Tween(begin: 0.0, end: 1.0),
|
||||||
|
builder: (context, value, child) {
|
||||||
|
return Opacity(
|
||||||
|
opacity: value,
|
||||||
|
child: Transform.translate(
|
||||||
|
offset: Offset(0, -20 * (1 - value)),
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.black87,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.2),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
message,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue