Revert "feat: 增加动画变量,处理多个变量控制动画逻辑"
This reverts commit aa0fd94cb29a197f2c48d39412e6eb0e8bfb6f5e.
This commit is contained in:
parent
961d419c4d
commit
8e27ddeded
@ -90,8 +90,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 是否显示延迟
|
// 是否显示延迟
|
||||||
final kr_isLatency = false.obs;
|
final kr_isLatency = false.obs;
|
||||||
|
|
||||||
final kr_isPositionAnimating = false.obs;
|
|
||||||
|
|
||||||
/// 默认
|
/// 默认
|
||||||
var kr_cutTag = ''.obs;
|
var kr_cutTag = ''.obs;
|
||||||
var kr_cutSeletedTag = ''.obs;
|
var kr_cutSeletedTag = ''.obs;
|
||||||
@ -220,16 +218,13 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
await _kr_prepareCountrySelectionBeforeStart();
|
await _kr_prepareCountrySelectionBeforeStart();
|
||||||
final selectedAfter =
|
final selectedAfter =
|
||||||
await KRSecureStorage().kr_readData(key: 'SELECTED_NODE_TAG');
|
await KRSecureStorage().kr_readData(key: 'SELECTED_NODE_TAG');
|
||||||
KRLogUtil.kr_i(
|
KRLogUtil.kr_i('准备后 SELECTED_NODE_TAG_autoConnect: ${selectedAfter ?? ''}',
|
||||||
'准备后 SELECTED_NODE_TAG_autoConnect: ${selectedAfter ?? ''}',
|
|
||||||
tag: 'HomeController');
|
tag: 'HomeController');
|
||||||
KRLogUtil.kr_i(
|
KRLogUtil.kr_i('准备后 kr_currentNodeName_autoConnect: ${kr_currentNodeName.value}',
|
||||||
'准备后 kr_currentNodeName_autoConnect: ${kr_currentNodeName.value}',
|
|
||||||
tag: 'HomeController');
|
tag: 'HomeController');
|
||||||
KRLogUtil.kr_i('准备后 kr_cutTag_autoConnect: ${kr_cutTag.value}',
|
KRLogUtil.kr_i('准备后 kr_cutTag_autoConnect: ${kr_cutTag.value}',
|
||||||
tag: 'HomeController');
|
tag: 'HomeController');
|
||||||
KRLogUtil.kr_i(
|
KRLogUtil.kr_i('准备后 kr_cutSeletedTag_autoConnect: ${kr_cutSeletedTag.value}',
|
||||||
'准备后 kr_cutSeletedTag_autoConnect: ${kr_cutSeletedTag.value}',
|
|
||||||
tag: 'HomeController');
|
tag: 'HomeController');
|
||||||
await kr_performNodeSwitch(selectedAfter!);
|
await kr_performNodeSwitch(selectedAfter!);
|
||||||
await KRSingBoxImp.instance.kr_start();
|
await KRSingBoxImp.instance.kr_start();
|
||||||
@ -320,42 +315,11 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 🔧 Android 15 新增:5秒后再次强制更新高度,兜底保护
|
// 🔧 Android 15 新增:5秒后再次强制更新高度,兜底保护
|
||||||
// Future.delayed(const Duration(seconds: 5), () {
|
Future.delayed(const Duration(seconds: 5), () {
|
||||||
// if (kr_bottomPanelHeight.value < 100) {
|
if (kr_bottomPanelHeight.value < 100) {
|
||||||
// KRLogUtil.kr_w('检测到底部面板高度异常(${kr_bottomPanelHeight.value}),强制修正',
|
KRLogUtil.kr_w('检测到底部面板高度异常(${kr_bottomPanelHeight.value}),强制修正',
|
||||||
// tag: 'HomeController');
|
tag: 'HomeController');
|
||||||
// kr_updateBottomPanelHeight();
|
kr_updateBottomPanelHeight();
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
_initShowAnimationWatcher();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _lastIsShow = false;
|
|
||||||
|
|
||||||
void _initShowAnimationWatcher() {
|
|
||||||
_lastIsShow = kr_currentNodeLatency.value == -1 || kr_isConnected.value;
|
|
||||||
everAll([kr_currentNodeLatency, kr_isConnected], (_) {
|
|
||||||
final v = kr_currentNodeLatency.value == -1 || kr_isConnected.value;
|
|
||||||
if (v != _lastIsShow) {
|
|
||||||
_triggerPositionAnim();
|
|
||||||
_lastIsShow = v;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void kr_onPositionAnimationEnd() {
|
|
||||||
kr_isPositionAnimating.value = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int _positionAnimToken = 0;
|
|
||||||
void _triggerPositionAnim() {
|
|
||||||
_positionAnimToken++;
|
|
||||||
final token = _positionAnimToken;
|
|
||||||
kr_isPositionAnimating.value = true;
|
|
||||||
Future.delayed(const Duration(milliseconds: 450), () {
|
|
||||||
if (_positionAnimToken == token) {
|
|
||||||
kr_isPositionAnimating.value = false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -974,26 +938,6 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
if (kDebugMode) {}
|
if (kDebugMode) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
DateTime? _lastConnectClickAt;
|
|
||||||
static const Duration _connectClickCooldown = Duration(milliseconds: 600);
|
|
||||||
|
|
||||||
bool kr_canProcessConnectClick() {
|
|
||||||
final now = DateTime.now();
|
|
||||||
if (kr_isPositionAnimating.value) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
final st = KRSingBoxImp.instance.kr_status.value;
|
|
||||||
if (st is SingboxStarting || st is SingboxStopping) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (_lastConnectClickAt != null &&
|
|
||||||
now.difference(_lastConnectClickAt!) < _connectClickCooldown) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_lastConnectClickAt = now;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 🔧 等待状态达到预期值
|
/// 🔧 等待状态达到预期值
|
||||||
Future<void> _waitForStatus(Type expectedType, {int maxSeconds = 3}) async {
|
Future<void> _waitForStatus(Type expectedType, {int maxSeconds = 3}) async {
|
||||||
if (kDebugMode) {}
|
if (kDebugMode) {}
|
||||||
@ -1204,9 +1148,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
/// 处理手动模式
|
/// 处理手动模式
|
||||||
void _kr_handleManualMode(dynamic element) {
|
void _kr_handleManualMode(dynamic element) {
|
||||||
try {
|
try {
|
||||||
KRLogUtil.kr_d(
|
KRLogUtil.kr_d('处理手动模式 - 内核选择: ${element.selected}, 用户选择: ${kr_cutTag.value}', tag: 'HomeController');
|
||||||
'处理手动模式 - 内核选择: ${element.selected}, 用户选择: ${kr_cutTag.value}',
|
|
||||||
tag: 'HomeController');
|
|
||||||
|
|
||||||
// 🔧 关键修复:不要用内核返回的 selected 覆盖用户手动选择
|
// 🔧 关键修复:不要用内核返回的 selected 覆盖用户手动选择
|
||||||
// 只有当内核返回的节点与用户选择一致时,才更新相关状态
|
// 只有当内核返回的节点与用户选择一致时,才更新相关状态
|
||||||
@ -1218,15 +1160,12 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
// 只有当内核确认切换成功时,才更新 UI 状态
|
// 只有当内核确认切换成功时,才更新 UI 状态
|
||||||
if (element.selected == kr_cutTag.value) {
|
if (element.selected == kr_cutTag.value) {
|
||||||
kr_cutSeletedTag.value = element.selected;
|
kr_cutSeletedTag.value = element.selected;
|
||||||
kr_currentNodeName.value =
|
kr_currentNodeName.value = kr_truncateText(element.selected, maxLength: 25);
|
||||||
kr_truncateText(element.selected, maxLength: 25);
|
|
||||||
// kr_moveToSelectedNode();
|
// kr_moveToSelectedNode();
|
||||||
KRLogUtil.kr_d('✅ 内核确认节点切换成功: ${element.selected}',
|
KRLogUtil.kr_d('✅ 内核确认节点切换成功: ${element.selected}', tag: 'HomeController');
|
||||||
tag: 'HomeController');
|
|
||||||
} else {
|
} else {
|
||||||
// 内核返回的节点与用户选择不一致,保持用户选择的显示
|
// 内核返回的节点与用户选择不一致,保持用户选择的显示
|
||||||
KRLogUtil.kr_d('⏳ 等待内核切换到用户选择的节点: ${kr_cutTag.value}',
|
KRLogUtil.kr_d('⏳ 等待内核切换到用户选择的节点: ${kr_cutTag.value}', tag: 'HomeController');
|
||||||
tag: 'HomeController');
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
KRLogUtil.kr_e('处理手动模式出错: $e', tag: 'HomeController');
|
KRLogUtil.kr_e('处理手动模式出错: $e', tag: 'HomeController');
|
||||||
@ -1425,12 +1364,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
// 🔒 节流控制:2秒内的重复切换请求直接忽略
|
// 🔒 节流控制:2秒内的重复切换请求直接忽略
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
if (_lastSwitchTime != null &&
|
if (_lastSwitchTime != null && now.difference(_lastSwitchTime!) < _switchThrottleDuration) {
|
||||||
now.difference(_lastSwitchTime!) < _switchThrottleDuration) {
|
final remainingTime = _switchThrottleDuration.inMilliseconds - now.difference(_lastSwitchTime!).inMilliseconds;
|
||||||
final remainingTime = _switchThrottleDuration.inMilliseconds -
|
KRLogUtil.kr_w('⚠️ 切换过于频繁,请等待 ${remainingTime}ms', tag: 'HomeController');
|
||||||
now.difference(_lastSwitchTime!).inMilliseconds;
|
|
||||||
KRLogUtil.kr_w('⚠️ 切换过于频繁,请等待 ${remainingTime}ms',
|
|
||||||
tag: 'HomeController');
|
|
||||||
KRCommonUtil.kr_showToast('切换过于频繁,请稍后再试');
|
KRCommonUtil.kr_showToast('切换过于频繁,请稍后再试');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1457,9 +1393,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
// 🔧 修复:保存节点选择以便VPN启动时应用
|
// 🔧 修复:保存节点选择以便VPN启动时应用
|
||||||
KRLogUtil.kr_i('💾 保存节点选择以便稍后应用: $tag', tag: 'HomeController');
|
KRLogUtil.kr_i('💾 保存节点选择以便稍后应用: $tag', tag: 'HomeController');
|
||||||
KRSecureStorage()
|
KRSecureStorage().kr_saveData(key: 'SELECTED_NODE_TAG', value: tag).then((_) {
|
||||||
.kr_saveData(key: 'SELECTED_NODE_TAG', value: tag)
|
|
||||||
.then((_) {
|
|
||||||
KRLogUtil.kr_i('✅ 节点选择已保存: $tag', tag: 'HomeController');
|
KRLogUtil.kr_i('✅ 节点选择已保存: $tag', tag: 'HomeController');
|
||||||
}).catchError((e) {
|
}).catchError((e) {
|
||||||
KRLogUtil.kr_e('❌ 保存节点选择失败: $e', tag: 'HomeController');
|
KRLogUtil.kr_e('❌ 保存节点选择失败: $e', tag: 'HomeController');
|
||||||
@ -1478,13 +1412,11 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
// 🔧 保存新节点选择
|
// 🔧 保存新节点选择
|
||||||
KRLogUtil.kr_i('💾 保存新节点选择: $tag', tag: 'HomeController');
|
KRLogUtil.kr_i('💾 保存新节点选择: $tag', tag: 'HomeController');
|
||||||
await KRSecureStorage()
|
await KRSecureStorage().kr_saveData(key: 'SELECTED_NODE_TAG', value: tag);
|
||||||
.kr_saveData(key: 'SELECTED_NODE_TAG', value: tag);
|
|
||||||
|
|
||||||
// 🚀 核心改进:使用 selectOutbound 进行热切换(参考 hiddify-app)
|
// 🚀 核心改进:使用 selectOutbound 进行热切换(参考 hiddify-app)
|
||||||
// 优势:不重启VPN,保持连接状态,切换瞬间完成,VPN开关不闪烁
|
// 优势:不重启VPN,保持连接状态,切换瞬间完成,VPN开关不闪烁
|
||||||
KRLogUtil.kr_i('🔄 [热切换] 调用 selectOutbound 切换节点...',
|
KRLogUtil.kr_i('🔄 [热切换] 调用 selectOutbound 切换节点...', tag: 'HomeController');
|
||||||
tag: 'HomeController');
|
|
||||||
|
|
||||||
// 🔧 关键修复:确定正确的 selector 组 tag
|
// 🔧 关键修复:确定正确的 selector 组 tag
|
||||||
// selectOutbound(groupTag, outboundTag) - 第一个参数是组的tag,不是节点的tag
|
// selectOutbound(groupTag, outboundTag) - 第一个参数是组的tag,不是节点的tag
|
||||||
@ -1495,14 +1427,12 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
for (var group in activeGroups) {
|
for (var group in activeGroups) {
|
||||||
if (group.type == ProxyType.selector) {
|
if (group.type == ProxyType.selector) {
|
||||||
selectorGroupTag = group.tag;
|
selectorGroupTag = group.tag;
|
||||||
KRLogUtil.kr_i('🔍 找到 selector 组: $selectorGroupTag',
|
KRLogUtil.kr_i('🔍 找到 selector 组: $selectorGroupTag', tag: 'HomeController');
|
||||||
tag: 'HomeController');
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KRLogUtil.kr_i('📡 调用 selectOutbound("$selectorGroupTag", "$tag")',
|
KRLogUtil.kr_i('📡 调用 selectOutbound("$selectorGroupTag", "$tag")', tag: 'HomeController');
|
||||||
tag: 'HomeController');
|
|
||||||
|
|
||||||
// 调用 sing-box 的 selectOutbound API
|
// 调用 sing-box 的 selectOutbound API
|
||||||
final result = await KRSingBoxImp.instance.kr_singBox
|
final result = await KRSingBoxImp.instance.kr_singBox
|
||||||
@ -1513,8 +1443,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
result.fold(
|
result.fold(
|
||||||
(error) {
|
(error) {
|
||||||
// 切换失败
|
// 切换失败
|
||||||
KRLogUtil.kr_e('❌ selectOutbound 调用失败: $error',
|
KRLogUtil.kr_e('❌ selectOutbound 调用失败: $error', tag: 'HomeController');
|
||||||
tag: 'HomeController');
|
|
||||||
throw Exception('节点切换失败: $error');
|
throw Exception('节点切换失败: $error');
|
||||||
},
|
},
|
||||||
(_) {
|
(_) {
|
||||||
@ -1541,14 +1470,11 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
orElse: () => throw Exception('未找到 selector 组'),
|
orElse: () => throw Exception('未找到 selector 组'),
|
||||||
);
|
);
|
||||||
|
|
||||||
KRLogUtil.kr_i(
|
KRLogUtil.kr_i('📊 [验证] ${selectGroup.tag}组当前选中: ${selectGroup.selected}', tag: 'HomeController');
|
||||||
'📊 [验证] ${selectGroup.tag}组当前选中: ${selectGroup.selected}',
|
|
||||||
tag: 'HomeController');
|
|
||||||
KRLogUtil.kr_i('📊 [验证] 目标节点: $tag', tag: 'HomeController');
|
KRLogUtil.kr_i('📊 [验证] 目标节点: $tag', tag: 'HomeController');
|
||||||
|
|
||||||
if (selectGroup.selected != tag) {
|
if (selectGroup.selected != tag) {
|
||||||
KRLogUtil.kr_w('⚠️ [验证] 节点选择验证失败,实际选中: ${selectGroup.selected}',
|
KRLogUtil.kr_w('⚠️ [验证] 节点选择验证失败,实际选中: ${selectGroup.selected}', tag: 'HomeController');
|
||||||
tag: 'HomeController');
|
|
||||||
// 不抛出异常,但记录警告
|
// 不抛出异常,但记录警告
|
||||||
} else {
|
} else {
|
||||||
KRLogUtil.kr_i('✅ [验证] 节点选择验证成功!', tag: 'HomeController');
|
KRLogUtil.kr_i('✅ [验证] 节点选择验证成功!', tag: 'HomeController');
|
||||||
@ -1562,6 +1488,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
KRLogUtil.kr_i('✅ 节点热切换成功,VPN保持连接: $tag', tag: 'HomeController');
|
KRLogUtil.kr_i('✅ 节点热切换成功,VPN保持连接: $tag', tag: 'HomeController');
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} catch (switchError) {
|
} catch (switchError) {
|
||||||
// 后台切换失败,恢复到原节点
|
// 后台切换失败,恢复到原节点
|
||||||
KRLogUtil.kr_e('❌ 后台节点切换失败: $switchError', tag: 'HomeController');
|
KRLogUtil.kr_e('❌ 后台节点切换失败: $switchError', tag: 'HomeController');
|
||||||
@ -1573,8 +1500,7 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
|
|||||||
|
|
||||||
// 恢复原节点选择
|
// 恢复原节点选择
|
||||||
try {
|
try {
|
||||||
await KRSecureStorage()
|
await KRSecureStorage().kr_saveData(key: 'SELECTED_NODE_TAG', value: originalTag);
|
||||||
.kr_saveData(key: 'SELECTED_NODE_TAG', value: originalTag);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
KRLogUtil.kr_e('❌ 恢复节点选择失败: $e', tag: 'HomeController');
|
KRLogUtil.kr_e('❌ 恢复节点选择失败: $e', tag: 'HomeController');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,50 +22,71 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
final _ = KRSingBoxImp.instance.kr_status.value;
|
final delay = controller.kr_currentNodeLatency.value;
|
||||||
|
|
||||||
|
// 🔧 关键: 强制读取两个 observable 确保追踪
|
||||||
|
final _ = KRSingBoxImp.instance.kr_status.value; // 强制追踪
|
||||||
|
final isConnected = controller.kr_isConnected.value; // 使用 controller 的状态
|
||||||
|
|
||||||
|
// 再次读取状态用于判断
|
||||||
|
final status = KRSingBoxImp.instance.kr_status.value;
|
||||||
|
final isSwitching = status is SingboxStarting || status is SingboxStopping;
|
||||||
|
|
||||||
|
print('🔵 Switch UI 更新: status=${status.runtimeType}, isConnected=$isConnected, isSwitching=$isSwitching');
|
||||||
|
|
||||||
|
final isShow = delay == -1 || isConnected;
|
||||||
|
|
||||||
|
final Color buttonColor = Theme.of(context).primaryColor;
|
||||||
final double screenWidth = Get.width;
|
final double screenWidth = Get.width;
|
||||||
final double screenHeight = Get.height;
|
final double screenHeight = Get.height;
|
||||||
|
|
||||||
final double buttonSize = 340;
|
final double buttonSize = 340;
|
||||||
final double currentButtonSize = 270;
|
final double currentButtonSize = isShow ? 270 : buttonSize;
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
AnimatedPositioned(
|
AnimatedPositioned(
|
||||||
duration: const Duration(milliseconds: 400),
|
duration: const Duration(milliseconds: 400),
|
||||||
curve: Curves.linear,
|
curve: Curves.linear,
|
||||||
left: (screenWidth - currentButtonSize) / 2,
|
left: isShow ? (screenWidth - currentButtonSize) / 2 : -60,
|
||||||
bottom: screenHeight * 0.2,
|
bottom: isShow ? screenHeight * 0.2 : -40,
|
||||||
onEnd: () {
|
|
||||||
controller.kr_onPositionAnimationEnd();
|
|
||||||
},
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
if (controller.kr_isPositionAnimating.value)
|
/// ✅ 呼吸同心圆背景
|
||||||
|
if (isShow)
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: OverflowBox(
|
child: OverflowBox(
|
||||||
maxWidth: buttonSize * 3,
|
maxWidth: buttonSize * 3,
|
||||||
maxHeight: buttonSize * 3,
|
maxHeight: buttonSize * 3,
|
||||||
child: ContinuousRippleEffect(
|
child: ContinuousRippleEffect(
|
||||||
color: Theme.of(context).primaryColor),
|
color: Theme.of(context).primaryColor
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
if (!isShow)
|
||||||
|
Positioned(
|
||||||
|
top: -20, // 距离顶部 10.w
|
||||||
|
left: 115, // 距离右侧 10.w
|
||||||
|
child: KrLocalImage(
|
||||||
|
imageName: "hi-home-slogan",
|
||||||
|
imageType: ImageType.svg,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
/// ✅ 按钮主体
|
||||||
Material(
|
Material(
|
||||||
shape: const CircleBorder(),
|
shape: const CircleBorder(),
|
||||||
color: Colors.transparent,
|
color: isShow ? Colors.transparent : Theme.of(context).primaryColor,
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
child: AbsorbPointer(
|
|
||||||
absorbing: controller.kr_isPositionAnimating.value,
|
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!controller.kr_canProcessConnectClick()) {
|
if(isSwitching) {
|
||||||
|
print('🔵 Switch UI 正在更新,切换中点击了按钮: status=${status.runtimeType}, isConnected=$isConnected, isSwitching=$isSwitching');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final current = controller
|
final current = controller.kr_subscribeService.kr_currentSubscribe.value;
|
||||||
.kr_subscribeService.kr_currentSubscribe.value;
|
|
||||||
bool hasValidSubscription = false;
|
bool hasValidSubscription = false;
|
||||||
if (current != null) {
|
if (current != null) {
|
||||||
DateTime? expire;
|
DateTime? expire;
|
||||||
@ -74,12 +95,10 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
|||||||
} catch (_) {
|
} catch (_) {
|
||||||
expire = null;
|
expire = null;
|
||||||
}
|
}
|
||||||
hasValidSubscription =
|
hasValidSubscription = expire != null && expire.isAfter(DateTime.now());
|
||||||
expire != null && expire.isAfter(DateTime.now());
|
|
||||||
}
|
}
|
||||||
if (hasValidSubscription) {
|
if (hasValidSubscription) {
|
||||||
controller.kr_toggleSwitch(
|
controller.kr_toggleSwitch(!controller.kr_isConnected.value);
|
||||||
!controller.kr_isConnected.value);
|
|
||||||
} else {
|
} else {
|
||||||
HIDialog.show(
|
HIDialog.show(
|
||||||
customMessageWidget: Padding(
|
customMessageWidget: Padding(
|
||||||
@ -88,10 +107,7 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
|||||||
'尚未购买套餐,请前往购买页面下单后即可开始极速网络体验',
|
'尚未购买套餐,请前往购买页面下单后即可开始极速网络体验',
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: KrAppTextStyle(
|
style: KrAppTextStyle(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context).textTheme.bodyMedium?.color,
|
||||||
.textTheme
|
|
||||||
.bodyMedium
|
|
||||||
?.color,
|
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@ -100,8 +116,7 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
|||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
confirmText: '前往',
|
confirmText: '前往',
|
||||||
onConfirm: () {
|
onConfirm: () {
|
||||||
GlobalOverlayService.instance
|
GlobalOverlayService.instance.triggerSubscriptionAnimation();
|
||||||
.triggerSubscriptionAnimation();
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -112,6 +127,8 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
|||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
if (isShow)
|
||||||
|
/// ✅ isShow = true,图片居中,文字贴近底部
|
||||||
Stack(
|
Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -131,25 +148,52 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
|||||||
controller.kr_connectText.value == '已连接'
|
controller.kr_connectText.value == '已连接'
|
||||||
? '已连接\n点击断开'
|
? '已连接\n点击断开'
|
||||||
: controller.kr_connectText.value,
|
: controller.kr_connectText.value,
|
||||||
key: ValueKey(
|
key: ValueKey(controller.kr_connectText.value),
|
||||||
controller.kr_connectText.value),
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
height: 1,
|
height: 1
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
)
|
||||||
|
else
|
||||||
|
/// ✅ isShow = false,恢复原本布局
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
KrLocalImage(
|
||||||
|
imageName: "hi-home-logo",
|
||||||
|
width: 104,
|
||||||
|
imageType: ImageType.svg,
|
||||||
|
),
|
||||||
|
SizedBox(height: 2.h),
|
||||||
|
Text(
|
||||||
|
controller.kr_connectText.value == '已连接'
|
||||||
|
? '已连接\n点击断开'
|
||||||
|
: controller.kr_connectText.value,
|
||||||
|
key: ValueKey(controller.kr_connectText.value),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 18.sp,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -158,7 +202,6 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ✅ 呼吸式同心圆动画(最小圆固定270,其他圆在270~479间波动,初始直径差10%)
|
/// ✅ 呼吸式同心圆动画(最小圆固定270,其他圆在270~479间波动,初始直径差10%)
|
||||||
/// ✅ 呼吸式同心圆动画(所有圆在270~470之间运动,起点相同但周期不同)
|
/// ✅ 呼吸式同心圆动画(所有圆在270~470之间运动,起点相同但周期不同)
|
||||||
class ContinuousRippleEffect extends StatefulWidget {
|
class ContinuousRippleEffect extends StatefulWidget {
|
||||||
@ -189,11 +232,10 @@ class _ContinuousRippleEffectState extends State<ContinuousRippleEffect>
|
|||||||
// 动画周期差异:外层慢,内层快
|
// 动画周期差异:外层慢,内层快
|
||||||
final duration = Duration(milliseconds: 3000 + i * 1200);
|
final duration = Duration(milliseconds: 3000 + i * 1200);
|
||||||
|
|
||||||
final controller = AnimationController(vsync: this, duration: duration)
|
final controller =
|
||||||
..repeat(reverse: true);
|
AnimationController(vsync: this, duration: duration)..repeat(reverse: true);
|
||||||
|
|
||||||
final curved =
|
final curved = CurvedAnimation(parent: controller, curve: Curves.easeInOutSine);
|
||||||
CurvedAnimation(parent: controller, curve: Curves.easeInOutSine);
|
|
||||||
_controllers.add(controller);
|
_controllers.add(controller);
|
||||||
_animations.add(curved);
|
_animations.add(curved);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user