219 lines
7.6 KiB
Dart
219 lines
7.6 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'package:get/get.dart';
|
||
import '../modules/kr_home/views/hi_subscription_corner_button.dart';
|
||
import 'package:kaer_with_panels/main.dart';
|
||
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
|
||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
||
|
||
class GlobalOverlayService extends GetxService {
|
||
Color? _currentColor;
|
||
|
||
static GlobalOverlayService get instance => Get.find<GlobalOverlayService>();
|
||
VoidCallback? _subscriptionAnimationTrigger;
|
||
|
||
void registerAnimationTrigger(VoidCallback trigger) {
|
||
_subscriptionAnimationTrigger = trigger;
|
||
}
|
||
|
||
/// 触发按钮动画跳转购买页
|
||
void triggerSubscriptionAnimation() {
|
||
if (_subscriptionAnimationTrigger != null) {
|
||
_subscriptionAnimationTrigger!.call();
|
||
} else {
|
||
print('🔥 Subscription animation trigger not registered yet');
|
||
}
|
||
}
|
||
OverlayEntry? _overlayEntry;
|
||
final RxBool _isVisible = false.obs;
|
||
final RxString _currentRoute = ''.obs;
|
||
|
||
bool get isVisible => _isVisible.value;
|
||
|
||
void updateCurrentRoute(String route) {
|
||
_currentRoute.value = route;
|
||
}
|
||
|
||
@override
|
||
void onInit() {
|
||
super.onInit();
|
||
print('🔥 GlobalOverlayService: Service initialized');
|
||
}
|
||
|
||
void showSubscriptionButton([OverlayState? overlay]) {
|
||
if (_isVisible.value) return;
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
_doShowSubscriptionButton(overlay);
|
||
});
|
||
}
|
||
|
||
void _doShowSubscriptionButton([OverlayState? overlay, Color? color]) {
|
||
print('🔥 _doShowSubscriptionButton called, overlay=$overlay');
|
||
|
||
if (_isVisible.value) return;
|
||
|
||
try {
|
||
overlay ??= navigatorKey.currentState?.overlay;
|
||
|
||
if (overlay == null) {
|
||
print('🔥 GlobalOverlayService: No overlay found, cannot show subscription button');
|
||
return;
|
||
}
|
||
|
||
_overlayEntry = OverlayEntry(
|
||
builder: (context) {
|
||
final statusBarHeight = MediaQuery.of(context).padding.top < 62 ? 62 : MediaQuery.of(context).padding.top;
|
||
final double radius = 40.0 + statusBarHeight;
|
||
final double diameter = radius * 2;
|
||
|
||
return Stack(
|
||
children: [
|
||
// 1️⃣ 圆背景,保持原来位置
|
||
Positioned(
|
||
top: -(diameter - (radius + statusBarHeight)),
|
||
right: -(radius - (statusBarHeight / 2)),
|
||
width: diameter,
|
||
height: diameter,
|
||
child: HISubscriptionCornerButton(
|
||
size: diameter,
|
||
color: _currentColor ?? Theme.of(context).primaryColor,
|
||
topOffset: -radius,
|
||
rightOffset: -radius,
|
||
),
|
||
),
|
||
|
||
// 2️⃣ money-icon,独立定位,固定在屏幕右上角
|
||
Positioned(
|
||
top: MediaQuery.of(context).padding.top,
|
||
right: (radius / 2),
|
||
child: FractionalTranslation(
|
||
// Offset 的第一个参数是 x,第二个是 y
|
||
// 0.5 代表向右偏移自身宽度的 50%,-0.5 代表向左偏移自身宽度的 50%
|
||
translation: const Offset(0.5, 0),
|
||
child: GestureDetector(
|
||
behavior: HitTestBehavior.translucent,
|
||
onTap: () {
|
||
print('🔥 money-icon tapped');
|
||
GlobalOverlayService.instance.triggerSubscriptionAnimation();
|
||
},
|
||
child: IgnorePointer(
|
||
ignoring: false,
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
KrLocalImage(
|
||
imageName: 'money-icon',
|
||
imageType: ImageType.svg,
|
||
width: 32.w, // 建议固定宽度以保证计算准确
|
||
),
|
||
SizedBox(height: 2.w),
|
||
Obx(() {
|
||
final current = _currentRoute.value;
|
||
print('🔥 GlobalOverlayService Obx: currentRoute = $current');
|
||
|
||
// ✅ 结合三种方式判断:1. 显式设为透明 2. 路由名称匹配 3. 包含关键特征
|
||
bool isHidden = _currentColor == Colors.transparent ||
|
||
current == Routes.KR_PURCHASE_MEMBERSHIP ||
|
||
current.contains(Routes.KR_PURCHASE_MEMBERSHIP) ||
|
||
Routes.KR_PURCHASE_MEMBERSHIP.contains(current) ||
|
||
current == Routes.KR_ORDER_STATUS ||
|
||
current.contains('purchase-membership');
|
||
|
||
if (isHidden) {
|
||
return const SizedBox.shrink();
|
||
}
|
||
|
||
return DefaultTextStyle(
|
||
style: const TextStyle(
|
||
decoration: TextDecoration.none, // 核心:显式声明无装饰
|
||
),
|
||
child: Text(
|
||
'购买套餐',
|
||
style: TextStyle(
|
||
color: Colors.black,
|
||
fontSize: 12.sp,
|
||
fontWeight: FontWeight.w600,
|
||
decoration: TextDecoration.none, // 也可以在这里直接写
|
||
),
|
||
),
|
||
);
|
||
}),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
);
|
||
},
|
||
);
|
||
|
||
overlay.insert(_overlayEntry!);
|
||
_isVisible.value = true;
|
||
print('🔥 GlobalOverlayService: Subscription button shown successfully');
|
||
} catch (e) {
|
||
print('🔥 GlobalOverlayService: Error showing subscription button: $e');
|
||
}
|
||
}
|
||
|
||
void hideSubscriptionButton() {
|
||
if (!_isVisible.value) return;
|
||
|
||
_overlayEntry?.remove();
|
||
_overlayEntry = null;
|
||
_isVisible.value = false;
|
||
}
|
||
|
||
void toggleSubscriptionButton() {
|
||
if (_isVisible.value) {
|
||
hideSubscriptionButton();
|
||
} else {
|
||
showSubscriptionButton();
|
||
}
|
||
}
|
||
|
||
void safeShowSubscriptionButton() {
|
||
void _attemptShow() {
|
||
final overlay = navigatorKey.currentState?.overlay;
|
||
if (overlay == null) {
|
||
print('🔥 Overlay not ready, retrying...');
|
||
Future.delayed(const Duration(milliseconds: 200), _attemptShow);
|
||
return;
|
||
}
|
||
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
print('🔥 Overlay ready, inserting subscription button');
|
||
showSubscriptionButton(overlay);
|
||
});
|
||
}
|
||
|
||
_attemptShow();
|
||
}
|
||
|
||
void updateSubscriptionButtonColor(Color? color) {
|
||
if (_overlayEntry == null) {
|
||
print('🔥 updateSubscriptionButtonColor: OverlayEntry is null');
|
||
return;
|
||
}
|
||
_currentColor = color;
|
||
_overlayEntry!.markNeedsBuild(); // 🔥 强制刷新 UI
|
||
}
|
||
|
||
|
||
void forceShowSubscriptionButton() {
|
||
print('🔥 GlobalOverlayService: Force showing subscription button');
|
||
hideSubscriptionButton();
|
||
Future.delayed(const Duration(milliseconds: 100), () {
|
||
safeShowSubscriptionButton();
|
||
});
|
||
}
|
||
|
||
@override
|
||
void onClose() {
|
||
hideSubscriptionButton();
|
||
super.onClose();
|
||
}
|
||
}
|