feat: 尚未购买的弹窗
This commit is contained in:
parent
adcde623c7
commit
55d7508807
@ -6,6 +6,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:kaer_with_panels/app/modules/hi_menu/controllers/hi_menu_controller.dart';
|
import 'package:kaer_with_panels/app/modules/hi_menu/controllers/hi_menu_controller.dart';
|
||||||
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
||||||
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
|
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
|
||||||
|
import 'package:kaer_with_panels/app/widgets/kr_subscription_expiry_text.dart';
|
||||||
|
|
||||||
/// 用户信息展示卡片 Widget
|
/// 用户信息展示卡片 Widget
|
||||||
///
|
///
|
||||||
@ -67,51 +68,10 @@ class UserInfoCard extends StatelessWidget {
|
|||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(() {
|
KRSubscriptionExpiryText(
|
||||||
final currentSubscribe =
|
expireTimeProvider: () => controller.kr_subscribeService
|
||||||
controller.kr_subscribeService.kr_currentSubscribe.value;
|
.kr_currentSubscribe.value?.expireTime,
|
||||||
String expiryText;
|
),
|
||||||
|
|
||||||
if (currentSubscribe == null) {
|
|
||||||
expiryText = '尚未购买套餐';
|
|
||||||
} else {
|
|
||||||
final now = DateTime.now();
|
|
||||||
DateTime? expireDateTime;
|
|
||||||
try {
|
|
||||||
expireDateTime =
|
|
||||||
DateTime.parse(currentSubscribe.expireTime);
|
|
||||||
} catch (e) {
|
|
||||||
expireDateTime = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expireDateTime == null) {
|
|
||||||
expiryText = '套餐信息无效';
|
|
||||||
} else if (expireDateTime.isBefore(now)) {
|
|
||||||
final formattedExpireDate =
|
|
||||||
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
|
||||||
expiryText = '已于 $formattedExpireDate 到期';
|
|
||||||
} else {
|
|
||||||
final year = expireDateTime.year;
|
|
||||||
final month = expireDateTime.month.toString().padLeft(2, '0');
|
|
||||||
final day = expireDateTime.day.toString().padLeft(2, '0');
|
|
||||||
final hour = expireDateTime.hour.toString().padLeft(2, '0');
|
|
||||||
final minute = expireDateTime.minute.toString().padLeft(2, '0');
|
|
||||||
final second = expireDateTime.second.toString().padLeft(2, '0');
|
|
||||||
|
|
||||||
// 2. 拼接成最终的字符串
|
|
||||||
final formattedDateTime = '$year/$month/$day $hour:$minute:$second';
|
|
||||||
|
|
||||||
expiryText = '到期时间:$formattedDateTime';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Text(
|
|
||||||
expiryText,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 12.sp,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -19,13 +19,14 @@ import 'package:kaer_with_panels/app/common/app_run_data.dart';
|
|||||||
import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_controller.dart';
|
import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_controller.dart';
|
||||||
import 'package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart';
|
import 'package:kaer_with_panels/app/widgets/dialogs/hi_dialog.dart';
|
||||||
import 'package:kaer_with_panels/app/common/app_config.dart';
|
import 'package:kaer_with_panels/app/common/app_config.dart';
|
||||||
|
import 'package:kaer_with_panels/app/widgets/kr_subscription_expiry_text.dart';
|
||||||
|
|
||||||
class HIUserInfoView extends GetView<HIUserInfoController> {
|
class HIUserInfoView extends GetView<HIUserInfoController> {
|
||||||
const HIUserInfoView({super.key});
|
const HIUserInfoView({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isDeviceLogin = KRAppRunData.getInstance().isDeviceLogin();
|
final isDeviceLogin = KRAppRunData.getInstance().isDeviceLogin();
|
||||||
return HIBaseScaffold(
|
return HIBaseScaffold(
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
@ -69,9 +70,14 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final account = KRAppRunData.getInstance().kr_account.value;
|
final account = KRAppRunData.getInstance()
|
||||||
final isDeviceLogin = account != null && account.startsWith('9000');
|
.kr_account
|
||||||
final accountText = isDeviceLogin ? '待绑定' : 'ID: ${KRAppRunData.getInstance().kr_account.value.toString()}';
|
.value;
|
||||||
|
final isDeviceLogin = account != null &&
|
||||||
|
account.startsWith('9000');
|
||||||
|
final accountText = isDeviceLogin
|
||||||
|
? '待绑定'
|
||||||
|
: 'ID: ${KRAppRunData.getInstance().kr_account.value.toString()}';
|
||||||
return Text(
|
return Text(
|
||||||
accountText,
|
accountText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@ -84,51 +90,13 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Obx(() {
|
KRSubscriptionExpiryText(
|
||||||
final currentSubscribe =
|
expireTimeProvider: () => controller
|
||||||
controller.kr_subscribeService.kr_currentSubscribe.value;
|
.kr_subscribeService
|
||||||
String expiryText;
|
.kr_currentSubscribe
|
||||||
|
.value
|
||||||
if (currentSubscribe == null) {
|
?.expireTime,
|
||||||
expiryText = '尚未购买套餐';
|
),
|
||||||
} else {
|
|
||||||
final now = DateTime.now();
|
|
||||||
DateTime? expireDateTime;
|
|
||||||
try {
|
|
||||||
expireDateTime =
|
|
||||||
DateTime.parse(currentSubscribe.expireTime);
|
|
||||||
} catch (e) {
|
|
||||||
expireDateTime = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expireDateTime == null) {
|
|
||||||
expiryText = '套餐信息无效';
|
|
||||||
} else if (expireDateTime.isBefore(now)) {
|
|
||||||
final formattedExpireDate =
|
|
||||||
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
|
||||||
expiryText = '已于 $formattedExpireDate 到期';
|
|
||||||
} else {
|
|
||||||
final year = expireDateTime.year;
|
|
||||||
final month = expireDateTime.month.toString().padLeft(2, '0');
|
|
||||||
final day = expireDateTime.day.toString().padLeft(2, '0');
|
|
||||||
final hour = expireDateTime.hour.toString().padLeft(2, '0');
|
|
||||||
final minute = expireDateTime.minute.toString().padLeft(2, '0');
|
|
||||||
final second = expireDateTime.second.toString().padLeft(2, '0');
|
|
||||||
|
|
||||||
// 2. 拼接成最终的字符串
|
|
||||||
final formattedDateTime = '$year/$month/$day $hour:$minute:$second';
|
|
||||||
|
|
||||||
expiryText = '到期时间:$formattedDateTime';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Text(
|
|
||||||
expiryText,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 12.sp,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -138,7 +106,8 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
SizedBox(height: 12.w),
|
SizedBox(height: 12.w),
|
||||||
// 动态:如果已有账号,显示“修改密码”,否则显示“绑定邮箱”
|
// 动态:如果已有账号,显示“修改密码”,否则显示“绑定邮箱”
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final isDeviceLogin = KRAppRunData.getInstance().isDeviceLogin();
|
final isDeviceLogin =
|
||||||
|
KRAppRunData.getInstance().isDeviceLogin();
|
||||||
if (!isDeviceLogin) return SizedBox.shrink();
|
if (!isDeviceLogin) return SizedBox.shrink();
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -155,14 +124,18 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: EdgeInsets.symmetric(horizontal: 0).copyWith(bottom: 10), // 在这里增加底部间距
|
margin: EdgeInsets.symmetric(horizontal: 0)
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
|
.copyWith(bottom: 10), // 在这里增加底部间距
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 16, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(22),
|
borderRadius: BorderRadius.circular(22),
|
||||||
border: Border.all(color: Colors.white, width: 2),
|
border:
|
||||||
|
Border.all(color: Colors.white, width: 2),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment:
|
||||||
|
MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
isDeviceLogin ? '绑定邮箱' : '修改密码',
|
isDeviceLogin ? '绑定邮箱' : '修改密码',
|
||||||
@ -203,7 +176,8 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
// 2. 让 GridView 根据内容自动调整高度
|
// 2. 让 GridView 根据内容自动调整高度
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
// 3. 设置网格的配置
|
// 3. 设置网格的配置
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
gridDelegate:
|
||||||
|
SliverGridDelegateWithFixedCrossAxisCount(
|
||||||
crossAxisCount: 2, // 强制两列
|
crossAxisCount: 2, // 强制两列
|
||||||
crossAxisSpacing: 10, // 水平间距
|
crossAxisSpacing: 10, // 水平间距
|
||||||
mainAxisSpacing: 10, // 垂直间距
|
mainAxisSpacing: 10, // 垂直间距
|
||||||
@ -226,8 +200,10 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
'请确认是否移除此设备?',
|
'请确认是否移除此设备?',
|
||||||
style: KrAppTextStyle(
|
style: KrAppTextStyle(
|
||||||
color:
|
color: Theme.of(context)
|
||||||
Theme.of(context).textTheme.bodyMedium?.color,
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.color,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@ -240,8 +216,7 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
},
|
},
|
||||||
onCancel: () {
|
onCancel: () {
|
||||||
controller.deleteDevice(id);
|
controller.deleteDevice(id);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -261,9 +236,11 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
),
|
),
|
||||||
// 👇 核心改动 3: 将固定在底部的按钮放在 Expanded 外部
|
// 👇 核心改动 3: 将固定在底部的按钮放在 Expanded 外部
|
||||||
Obx(() {
|
Obx(() {
|
||||||
if((KRAppRunData.getInstance().kr_account.value != null &&
|
if ((KRAppRunData.getInstance().kr_account.value != null &&
|
||||||
KRAppRunData.getInstance().kr_account.value!.startsWith('9000')))
|
KRAppRunData.getInstance()
|
||||||
return SizedBox.shrink();
|
.kr_account
|
||||||
|
.value!
|
||||||
|
.startsWith('9000'))) return SizedBox.shrink();
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 40.w),
|
padding: EdgeInsets.symmetric(horizontal: 40.w),
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -278,7 +255,10 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
'注销账号后,所有此账号内的剩余套餐和账户数据将被清空,无法找回。', // 1. 修改为正确的提示信息
|
'注销账号后,所有此账号内的剩余套餐和账户数据将被清空,无法找回。', // 1. 修改为正确的提示信息
|
||||||
textAlign: TextAlign.left, // 文本居中
|
textAlign: TextAlign.left, // 文本居中
|
||||||
style: KrAppTextStyle(
|
style: KrAppTextStyle(
|
||||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
color: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.color,
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@ -292,8 +272,7 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
Get.toNamed(Routes.KR_DELETE_ACCOUNT);
|
Get.toNamed(Routes.KR_DELETE_ACCOUNT);
|
||||||
},
|
},
|
||||||
// 4. onConfirm 对应“返回”按钮的点击事件
|
// 4. onConfirm 对应“返回”按钮的点击事件
|
||||||
onConfirm: () {
|
onConfirm: () {},
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -301,7 +280,8 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
padding: EdgeInsets.symmetric(vertical: 12.w),
|
padding: EdgeInsets.symmetric(vertical: 12.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(24.w),
|
borderRadius: BorderRadius.circular(24.w),
|
||||||
border: Border.all(color: const Color(0xFFFF2ED1), width: 2),
|
border: Border.all(
|
||||||
|
color: const Color(0xFFFF2ED1), width: 2),
|
||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -324,7 +304,10 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
'确认要退出您的账号?', // 1. 修改为正确的提示信息
|
'确认要退出您的账号?', // 1. 修改为正确的提示信息
|
||||||
textAlign: TextAlign.center, // 文本居中
|
textAlign: TextAlign.center, // 文本居中
|
||||||
style: KrAppTextStyle(
|
style: KrAppTextStyle(
|
||||||
color: Theme.of(context).textTheme.bodyMedium?.color,
|
color: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyMedium
|
||||||
|
?.color,
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@ -333,15 +316,14 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
cancelText: '确认',
|
cancelText: '确认',
|
||||||
confirmText: '返回',
|
confirmText: '返回',
|
||||||
onCancel: () async {
|
onCancel: () async {
|
||||||
final currentDevice = controller.devices.firstWhere(
|
final currentDevice =
|
||||||
(device) => device['is_current'] == true,
|
controller.devices.firstWhere(
|
||||||
|
(device) => device['is_current'] == true,
|
||||||
);
|
);
|
||||||
final deviceId = currentDevice['id'] as String;
|
final deviceId = currentDevice['id'] as String;
|
||||||
await controller.deleteDevice(deviceId);
|
await controller.deleteDevice(deviceId);
|
||||||
},
|
},
|
||||||
onConfirm: () {
|
onConfirm: () {},
|
||||||
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -376,6 +358,7 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 构建“当前设备信息卡”的私有方法
|
/// 构建“当前设备信息卡”的私有方法
|
||||||
Widget _buildDeviceCard({
|
Widget _buildDeviceCard({
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
@ -396,7 +379,8 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
final deviceType = deviceInfo['type'] as String;
|
final deviceType = deviceInfo['type'] as String;
|
||||||
final iconName = deviceInfo['icon'] as String;
|
final iconName = deviceInfo['icon'] as String;
|
||||||
|
|
||||||
return Stack( // 使用 Stack 来放置删除按钮
|
return Stack(
|
||||||
|
// 使用 Stack 来放置删除按钮
|
||||||
children: [
|
children: [
|
||||||
// 主体内容容器
|
// 主体内容容器
|
||||||
Container(
|
Container(
|
||||||
@ -486,31 +470,31 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
// 在这里处理点击“添加设备”的逻辑
|
// 在这里处理点击“添加设备”的逻辑
|
||||||
final device_limit = AppConfig.getInstance().device_limit;
|
final device_limit = AppConfig.getInstance().device_limit;
|
||||||
HIDialog.show(
|
HIDialog.show(
|
||||||
customMessageWidget: Padding(
|
customMessageWidget: Padding(
|
||||||
padding: EdgeInsets.only(top: 16.w, bottom: 16.w),
|
padding: EdgeInsets.only(top: 16.w, bottom: 16.w),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min, // 让 Column 高度包裹内容
|
mainAxisSize: MainAxisSize.min, // 让 Column 高度包裹内容
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// 2. 第一个 Text 组件
|
// 2. 第一个 Text 组件
|
||||||
Text(
|
Text(
|
||||||
'请使用绑定邮箱登录新设备',
|
'请使用绑定邮箱登录新设备',
|
||||||
style: KrAppTextStyle(
|
style: KrAppTextStyle(
|
||||||
color: Colors.black, // 可以使用稍浅
|
color: Colors.black, // 可以使用稍浅
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
|
||||||
),
|
),
|
||||||
SizedBox(height: 20.w),
|
),
|
||||||
Text(
|
SizedBox(height: 20.w),
|
||||||
"每个账号最多允许同时使用${device_limit}台设备同时在线",
|
Text(
|
||||||
style: KrAppTextStyle(
|
"每个账号最多允许同时使用${device_limit}台设备同时在线",
|
||||||
color: Colors.black,
|
style: KrAppTextStyle(
|
||||||
fontSize: 14.sp,
|
color: Colors.black,
|
||||||
fontWeight: FontWeight.w600,
|
fontSize: 14.sp,
|
||||||
),
|
fontWeight: FontWeight.w600,
|
||||||
)
|
),
|
||||||
/*Obx(() {
|
)
|
||||||
|
/*Obx(() {
|
||||||
// final current = controller.kr_subscribeService.kr_currentSubscribe.value;
|
// final current = controller.kr_subscribeService.kr_currentSubscribe.value;
|
||||||
|
|
||||||
// 如果 current 为 null,显示默认值 0
|
// 如果 current 为 null,显示默认值 0
|
||||||
@ -518,9 +502,9 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}),*/
|
}),*/
|
||||||
],
|
],
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
confirmText: KRAppRunData.getInstance().isDeviceLogin() ? '前往' : null,
|
confirmText: KRAppRunData.getInstance().isDeviceLogin() ? '前往' : null,
|
||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
onConfirm: () {
|
onConfirm: () {
|
||||||
@ -591,7 +575,7 @@ class HIUserInfoView extends GetView<HIUserInfoController> {
|
|||||||
final RegExp regExp = RegExp(r'\((.*?)\)');
|
final RegExp regExp = RegExp(r'\((.*?)\)');
|
||||||
final Match? match = regExp.firstMatch(deviceName);
|
final Match? match = regExp.firstMatch(deviceName);
|
||||||
|
|
||||||
if (match != null && match.groupCount >= 1 ) {
|
if (match != null && match.groupCount >= 1) {
|
||||||
// 获取括号内内容
|
// 获取括号内内容
|
||||||
final inside = match.group(1)!; // "Android; google Pixel 9; 15"
|
final inside = match.group(1)!; // "Android; google Pixel 9; 15"
|
||||||
|
|
||||||
|
|||||||
@ -4,11 +4,11 @@ import 'package:get/get.dart';
|
|||||||
import 'package:kaer_with_panels/app/common/app_run_data.dart';
|
import 'package:kaer_with_panels/app/common/app_run_data.dart';
|
||||||
import 'package:kaer_with_panels/app/widgets/hi_base_scaffold.dart';
|
import 'package:kaer_with_panels/app/widgets/hi_base_scaffold.dart';
|
||||||
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
|
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
|
||||||
|
import 'package:kaer_with_panels/app/widgets/kr_subscription_expiry_text.dart';
|
||||||
import '../controllers/kr_delete_account_controller.dart';
|
import '../controllers/kr_delete_account_controller.dart';
|
||||||
import 'package:kaer_with_panels/app/localization/app_translations.dart';
|
import 'package:kaer_with_panels/app/localization/app_translations.dart';
|
||||||
import 'package:kaer_with_panels/app/widgets/kr_app_text_style.dart';
|
import 'package:kaer_with_panels/app/widgets/kr_app_text_style.dart';
|
||||||
|
|
||||||
|
|
||||||
class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
||||||
const KRDeleteAccountView({super.key});
|
const KRDeleteAccountView({super.key});
|
||||||
|
|
||||||
@ -46,7 +46,8 @@ class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
|||||||
padding: EdgeInsets.symmetric(vertical: 12.w),
|
padding: EdgeInsets.symmetric(vertical: 12.w),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(24.w),
|
borderRadius: BorderRadius.circular(24.w),
|
||||||
border: Border.all(color: const Color(0xFFFF2ED1), width: 2),
|
border:
|
||||||
|
Border.all(color: const Color(0xFFFF2ED1), width: 2),
|
||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -87,7 +88,6 @@ class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget _buildUserInfoSection() {
|
Widget _buildUserInfoSection() {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
@ -129,12 +129,16 @@ class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final _ = KRAppRunData.getInstance().kr_isLogin.value;
|
final account = KRAppRunData.getInstance()
|
||||||
final userId = (KRAppRunData.getInstance().kr_userId.value ?? '').toString();
|
.kr_account
|
||||||
final deviceId = KRAppRunData.getInstance().deviceId ?? '';
|
.value;
|
||||||
|
final isDeviceLogin = account != null &&
|
||||||
|
account.startsWith('9000');
|
||||||
|
final accountText = isDeviceLogin
|
||||||
|
? '待绑定'
|
||||||
|
: 'ID: ${KRAppRunData.getInstance().kr_account.value.toString()}';
|
||||||
return Text(
|
return Text(
|
||||||
'ID: ${userId.isNotEmpty ? userId : deviceId}',
|
accountText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white.withOpacity(0.85),
|
color: Colors.white.withOpacity(0.85),
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
@ -142,51 +146,14 @@ class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Obx(() {
|
KRSubscriptionExpiryText(
|
||||||
final currentSubscribe =
|
expireTimeProvider: () => controller
|
||||||
controller.kr_subscribeService.kr_currentSubscribe.value;
|
.kr_subscribeService.kr_currentSubscribe.value?.expireTime,
|
||||||
String expiryText;
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
if (currentSubscribe == null) {
|
fontSize: 12.sp,
|
||||||
expiryText = '尚未购买套餐';
|
),
|
||||||
} else {
|
),
|
||||||
final now = DateTime.now();
|
|
||||||
DateTime? expireDateTime;
|
|
||||||
try {
|
|
||||||
expireDateTime =
|
|
||||||
DateTime.parse(currentSubscribe.expireTime);
|
|
||||||
} catch (e) {
|
|
||||||
expireDateTime = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expireDateTime == null) {
|
|
||||||
expiryText = '套餐信息无效';
|
|
||||||
} else if (expireDateTime.isBefore(now)) {
|
|
||||||
final formattedExpireDate =
|
|
||||||
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
|
||||||
expiryText = '已于 $formattedExpireDate 到期';
|
|
||||||
} else {
|
|
||||||
expiryText = '到期时间:${expireDateTime}';final year = expireDateTime.year;
|
|
||||||
final month = expireDateTime.month.toString().padLeft(2, '0');
|
|
||||||
final day = expireDateTime.day.toString().padLeft(2, '0');
|
|
||||||
final hour = expireDateTime.hour.toString().padLeft(2, '0');
|
|
||||||
final minute = expireDateTime.minute.toString().padLeft(2, '0');
|
|
||||||
final second = expireDateTime.second.toString().padLeft(2, '0');
|
|
||||||
|
|
||||||
// 2. 拼接成最终的字符串
|
|
||||||
final formattedDateTime = '$year/$month/$day $hour:$minute:$second';
|
|
||||||
|
|
||||||
expiryText = '到期时间:$formattedDateTime';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Text(
|
|
||||||
expiryText,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 12.sp,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -213,7 +180,8 @@ class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
|||||||
color: const Color(0xFFA6A6A6),
|
color: const Color(0xFFA6A6A6),
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.w),
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.w),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(25.w),
|
borderRadius: BorderRadius.circular(25.w),
|
||||||
borderSide: BorderSide(color: Colors.white, width: 2),
|
borderSide: BorderSide(color: Colors.white, width: 2),
|
||||||
@ -233,14 +201,15 @@ class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
|||||||
suffixIcon: Padding(
|
suffixIcon: Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
|
padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
|
||||||
child: Obx(() {
|
child: Obx(() {
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: controller.kr_canSendCode.value ? controller.kr_sendCode : null,
|
onTap: controller.kr_canSendCode.value
|
||||||
|
? controller.kr_sendCode
|
||||||
|
: null,
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 100.w,
|
width: 100.w,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: controller.kr_canSendCode.value
|
color: controller.kr_canSendCode.value
|
||||||
? Theme.of(Get.context!).primaryColor
|
? Theme.of(Get.context!).primaryColor
|
||||||
: const Color(0xFFD5D5D5),
|
: const Color(0xFFD5D5D5),
|
||||||
borderRadius: BorderRadius.circular(100.r), // 药丸状
|
borderRadius: BorderRadius.circular(100.r), // 药丸状
|
||||||
@ -254,7 +223,7 @@ class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
|
|||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: controller.kr_canSendCode.value
|
color: controller.kr_canSendCode.value
|
||||||
? Colors.black
|
? Colors.black
|
||||||
: const Color(0xFF464655) ,
|
: const Color(0xFF464655),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -86,8 +86,17 @@ class HIAnimatedConnectButton extends GetView<KRHomeController> {
|
|||||||
print('🔵 Switch UI 正在更新,切换中点击了按钮: status=${status.runtimeType}, isConnected=$isConnected, isSwitching=$isSwitching');
|
print('🔵 Switch UI 正在更新,切换中点击了按钮: status=${status.runtimeType}, isConnected=$isConnected, isSwitching=$isSwitching');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final hasValidSubscription =
|
final current = controller.kr_subscribeService.kr_currentSubscribe.value;
|
||||||
controller.kr_subscribeService.kr_availableSubscribes.isNotEmpty;
|
bool hasValidSubscription = false;
|
||||||
|
if (current != null) {
|
||||||
|
DateTime? expire;
|
||||||
|
try {
|
||||||
|
expire = DateTime.parse(current.expireTime);
|
||||||
|
} catch (_) {
|
||||||
|
expire = null;
|
||||||
|
}
|
||||||
|
hasValidSubscription = expire != null && expire.isAfter(DateTime.now());
|
||||||
|
}
|
||||||
if (hasValidSubscription) {
|
if (hasValidSubscription) {
|
||||||
controller.kr_toggleSwitch(!controller.kr_isConnected.value);
|
controller.kr_toggleSwitch(!controller.kr_isConnected.value);
|
||||||
} else {
|
} else {
|
||||||
@ -291,4 +300,3 @@ class _ContinuousRippleEffectState extends State<ContinuousRippleEffect>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,6 @@ import 'kr_home_subscription_view.dart';
|
|||||||
import './hi_animated_connect_button.dart';
|
import './hi_animated_connect_button.dart';
|
||||||
import 'package:kaer_with_panels/app/services/global_overlay_service.dart';
|
import 'package:kaer_with_panels/app/services/global_overlay_service.dart';
|
||||||
|
|
||||||
|
|
||||||
class KRHomeView extends StatefulWidget {
|
class KRHomeView extends StatefulWidget {
|
||||||
const KRHomeView({super.key});
|
const KRHomeView({super.key});
|
||||||
|
|
||||||
@ -35,8 +34,6 @@ class _KRHomeViewState extends State<KRHomeView> {
|
|||||||
controller = Get.find<KRHomeController>();
|
controller = Get.find<KRHomeController>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
@ -50,174 +47,186 @@ class _KRHomeViewState extends State<KRHomeView> {
|
|||||||
children: [
|
children: [
|
||||||
HIBaseScaffold(
|
HIBaseScaffold(
|
||||||
showMenuButton: true,
|
showMenuButton: true,
|
||||||
topContentAreaHeight: 80,
|
topContentAreaHeight: 80,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
fit: StackFit.expand,
|
fit: StackFit.expand,
|
||||||
children: [
|
children: [
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.topLeft,
|
alignment: Alignment.topLeft,
|
||||||
child:
|
child: SafeArea(
|
||||||
SafeArea(
|
child: Padding(
|
||||||
child: Padding(
|
padding: EdgeInsets.fromLTRB(40.w, 8.w, 0, 0),
|
||||||
padding: EdgeInsets.fromLTRB(40.w, 8.w, 0, 0),
|
child: Column(
|
||||||
child: Column(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
mainAxisSize: MainAxisSize.min,
|
||||||
mainAxisSize: MainAxisSize.min,
|
children: [
|
||||||
children: [
|
Text(
|
||||||
Text(
|
'Hi快VPN-网在我在,网快我快',
|
||||||
'Hi快VPN-网在我在,网快我快',
|
style: TextStyle(
|
||||||
style: TextStyle(
|
color: Colors.white,
|
||||||
color: Colors.white,
|
fontSize: 14.sp,
|
||||||
fontSize: 14.sp,
|
fontWeight: FontWeight.w600,
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
// 订阅信息
|
|
||||||
Obx(() {
|
|
||||||
// 1. 先获取订阅信息
|
|
||||||
final currentSubscribe =
|
|
||||||
controller.kr_subscribeService.kr_currentSubscribe.value;
|
|
||||||
|
|
||||||
// 2. 准备一个 Widget 变量,用于存放最终要显示的内容
|
|
||||||
Widget content;
|
|
||||||
|
|
||||||
// --- 定义统一的文本样式,并设置行高 ---
|
|
||||||
final textStyle = TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 12.sp,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
height: 1.2, // 您可以微调这个值来达到想要的视觉效果
|
|
||||||
);
|
|
||||||
|
|
||||||
// 3. 开始条件判断
|
|
||||||
if (currentSubscribe == null) {
|
|
||||||
// --- 情况1: 没有任何订阅信息 ---
|
|
||||||
content = Text(
|
|
||||||
'尚未购买套餐',
|
|
||||||
style: textStyle,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// --- 情况2: 有订阅信息,需要判断是否过期 ---
|
|
||||||
final now = DateTime.now();
|
|
||||||
DateTime? expireDateTime;
|
|
||||||
try {
|
|
||||||
expireDateTime = DateTime.parse(currentSubscribe.expireTime);
|
|
||||||
} catch (e) {
|
|
||||||
// 日期格式解析失败
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expireDateTime != null && expireDateTime.isBefore(now)) {
|
|
||||||
// --- 情况2.1: 订阅已过期 ---
|
|
||||||
final formattedExpireDate =
|
|
||||||
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
|
||||||
// 使用换行符 \n 合并为单个 Text 组件
|
|
||||||
content = Text(
|
|
||||||
'您的套餐已于 $formattedExpireDate 到期\n请前往购买新套餐',
|
|
||||||
style: textStyle,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// --- 情况2.2: 订阅有效 ---
|
|
||||||
final difference = expireDateTime?.difference(now);
|
|
||||||
final remainingDaysText = (difference?.inDays ?? 0) > 0
|
|
||||||
? '${difference!.inDays} 天'
|
|
||||||
: '不足一天';
|
|
||||||
// 使用换行符 \n 合并为单个 Text 组件
|
|
||||||
content = Text(
|
|
||||||
'套餐剩余:$remainingDaysText\n${controller.kr_isConnected.value ? '当前线路:${controller.kr_getRealConnectedNodeCountry()}' : '未连接'}',
|
|
||||||
style: textStyle,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 返回包裹在公共 Container 中的最终内容
|
|
||||||
return Container(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
padding: EdgeInsets.only(top: 8.h),
|
|
||||||
child: content,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
SizedBox(height: 8.h), // 添加一些垂直间距
|
|
||||||
|
|
||||||
// --- 自定义“闪连”Checkbox ---
|
|
||||||
Obx(() {
|
|
||||||
return Row(
|
|
||||||
mainAxisSize: MainAxisSize.min, // 让 Row 的宽度包裹其内容
|
|
||||||
children: [
|
|
||||||
// --- 可点击的 Checkbox 区域 ---
|
|
||||||
GestureDetector(
|
|
||||||
// 点击方框和文字都可以切换状态
|
|
||||||
onTap: () => controller.toggleQuickConnect(!controller.isQuickConnectEnabled.value),
|
|
||||||
child: AbsorbPointer(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
// 1. 自定义 Checkbox 的方框外观
|
|
||||||
Container(
|
|
||||||
width: 20.w,
|
|
||||||
height: 20.w,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: controller.isQuickConnectEnabled.value
|
|
||||||
? Theme.of(context).primaryColor
|
|
||||||
: Colors.transparent,
|
|
||||||
border: Border.all(
|
|
||||||
color: Theme.of(context).primaryColor,
|
|
||||||
width: 1.5,
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(4.r),
|
|
||||||
),
|
|
||||||
child: controller.isQuickConnectEnabled.value
|
|
||||||
? Icon(
|
|
||||||
Icons.check,
|
|
||||||
size: 14.w,
|
|
||||||
color: Colors.black,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
SizedBox(width: 8.w),
|
|
||||||
// 2. “闪连”标签
|
|
||||||
Text(
|
|
||||||
'闪连',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 20.sp,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
// --- 问号图标和点击弹窗区域 ---
|
),
|
||||||
SizedBox(width: 6.w), // 文字和问号图标之间的间距
|
// 订阅信息
|
||||||
GestureDetector(
|
Obx(() {
|
||||||
onTap: () {
|
// 1. 先获取订阅信息
|
||||||
HIDialog.show(
|
final currentSubscribe = controller
|
||||||
title: '*闪连功能',
|
.kr_subscribeService.kr_currentSubscribe.value;
|
||||||
message: '开启后,每次打开软件默认自动连接,无需点击连接按钮\n在后台关闭软件后,软件将自动断开',
|
|
||||||
|
// 2. 准备一个 Widget 变量,用于存放最终要显示的内容
|
||||||
|
Widget content;
|
||||||
|
|
||||||
|
// --- 定义统一的文本样式,并设置行高 ---
|
||||||
|
final normalStyle = TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 12.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
height: 1.2,
|
||||||
|
);
|
||||||
|
final highlightStyle = normalStyle.copyWith(
|
||||||
|
color: const Color(0xFFFF00B7),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. 开始条件判断
|
||||||
|
if (currentSubscribe == null) {
|
||||||
|
// --- 情况1: 没有任何订阅信息 ---
|
||||||
|
content = Text(
|
||||||
|
'尚未购买套餐',
|
||||||
|
style: highlightStyle,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// --- 情况2: 有订阅信息,需要判断是否过期 ---
|
||||||
|
final now = DateTime.now();
|
||||||
|
DateTime? expireDateTime;
|
||||||
|
try {
|
||||||
|
expireDateTime =
|
||||||
|
DateTime.parse(currentSubscribe.expireTime);
|
||||||
|
} catch (e) {
|
||||||
|
// 日期格式解析失败
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expireDateTime != null &&
|
||||||
|
expireDateTime.isBefore(now)) {
|
||||||
|
// --- 情况2.1: 订阅已过期 ---
|
||||||
|
final formattedExpireDate =
|
||||||
|
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
||||||
|
// 使用换行符 \n 合并为单个 Text 组件
|
||||||
|
content = Text(
|
||||||
|
'您的套餐已于 $formattedExpireDate 到期\n请前往购买新套餐',
|
||||||
|
style: highlightStyle,
|
||||||
);
|
);
|
||||||
},
|
} else {
|
||||||
child: KrLocalImage(
|
// --- 情况2.2: 订阅有效 ---
|
||||||
imageName: 'question-icon', // 图片名称
|
final difference =
|
||||||
imageType: ImageType.svg, // 图片类型
|
expireDateTime?.difference(now);
|
||||||
width: 24.w,
|
final remainingDaysText =
|
||||||
height: 24.w,
|
(difference?.inDays ?? 0) > 0
|
||||||
color: Colors.white, // 让图标颜色与边框协调
|
? '${difference!.inDays} 天'
|
||||||
),
|
: '不足一天';
|
||||||
),
|
// 使用换行符 \n 合并为单个 Text 组件
|
||||||
],
|
content = Text(
|
||||||
);
|
'套餐剩余:$remainingDaysText\n${controller.kr_isConnected.value ? '当前线路:${controller.kr_getRealConnectedNodeCountry()}' : '未连接'}',
|
||||||
}),
|
style: normalStyle,
|
||||||
],
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 返回包裹在公共 Container 中的最终内容
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
padding: EdgeInsets.only(top: 8.h),
|
||||||
|
child: content,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
SizedBox(height: 8.h), // 添加一些垂直间距
|
||||||
|
|
||||||
|
// --- 自定义“闪连”Checkbox ---
|
||||||
|
Obx(() {
|
||||||
|
return Row(
|
||||||
|
mainAxisSize: MainAxisSize.min, // 让 Row 的宽度包裹其内容
|
||||||
|
children: [
|
||||||
|
// --- 可点击的 Checkbox 区域 ---
|
||||||
|
GestureDetector(
|
||||||
|
// 点击方框和文字都可以切换状态
|
||||||
|
onTap: () => controller.toggleQuickConnect(
|
||||||
|
!controller.isQuickConnectEnabled.value),
|
||||||
|
child: AbsorbPointer(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
// 1. 自定义 Checkbox 的方框外观
|
||||||
|
Container(
|
||||||
|
width: 20.w,
|
||||||
|
height: 20.w,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: controller
|
||||||
|
.isQuickConnectEnabled.value
|
||||||
|
? Theme.of(context).primaryColor
|
||||||
|
: Colors.transparent,
|
||||||
|
border: Border.all(
|
||||||
|
color:
|
||||||
|
Theme.of(context).primaryColor,
|
||||||
|
width: 1.5,
|
||||||
|
),
|
||||||
|
borderRadius:
|
||||||
|
BorderRadius.circular(4.r),
|
||||||
|
),
|
||||||
|
child: controller
|
||||||
|
.isQuickConnectEnabled.value
|
||||||
|
? Icon(
|
||||||
|
Icons.check,
|
||||||
|
size: 14.w,
|
||||||
|
color: Colors.black,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8.w),
|
||||||
|
// 2. “闪连”标签
|
||||||
|
Text(
|
||||||
|
'闪连',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 20.sp,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// --- 问号图标和点击弹窗区域 ---
|
||||||
|
SizedBox(width: 6.w), // 文字和问号图标之间的间距
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
HIDialog.show(
|
||||||
|
title: '*闪连功能',
|
||||||
|
message:
|
||||||
|
'开启后,每次打开软件默认自动连接,无需点击连接按钮\n在后台关闭软件后,软件将自动断开',
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: KrLocalImage(
|
||||||
|
imageName: 'question-icon', // 图片名称
|
||||||
|
imageType: ImageType.svg, // 图片类型
|
||||||
|
width: 24.w,
|
||||||
|
height: 24.w,
|
||||||
|
color: Colors.white, // 让图标颜色与边框协调
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
// 将 HIAnimatedConnectButton 移到 HIBaseScaffold 外部,避免 SafeArea 约束
|
||||||
),
|
HIAnimatedConnectButton(),
|
||||||
// 将 HIAnimatedConnectButton 移到 HIBaseScaffold 外部,避免 SafeArea 约束
|
],
|
||||||
HIAnimatedConnectButton(),
|
);
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import 'package:kaer_with_panels/app/common/app_run_data.dart';
|
|||||||
import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_controller.dart';
|
import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_controller.dart';
|
||||||
import 'package:kaer_with_panels/app/services/kr_site_config_service.dart';
|
import 'package:kaer_with_panels/app/services/kr_site_config_service.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:kaer_with_panels/app/widgets/kr_subscription_expiry_text.dart';
|
||||||
|
|
||||||
class KRLoginView extends GetView<KRLoginController> {
|
class KRLoginView extends GetView<KRLoginController> {
|
||||||
const KRLoginView({super.key});
|
const KRLoginView({super.key});
|
||||||
@ -19,7 +20,8 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isKeyboardVisible = MediaQuery.of(context).viewInsets.bottom > 0;
|
final isKeyboardVisible = MediaQuery.of(context).viewInsets.bottom > 0;
|
||||||
final isHideBack = (Get.arguments as Map<String, dynamic>?)?['is-back'] ?? false;
|
final isHideBack =
|
||||||
|
(Get.arguments as Map<String, dynamic>?)?['is-back'] ?? false;
|
||||||
return HIBaseScaffold(
|
return HIBaseScaffold(
|
||||||
showBack: !isHideBack,
|
showBack: !isHideBack,
|
||||||
resizeToAvoidBottomInset: true,
|
resizeToAvoidBottomInset: true,
|
||||||
@ -27,7 +29,9 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
children: [
|
children: [
|
||||||
SingleChildScrollView(
|
SingleChildScrollView(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 40.w,),
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 40.w,
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// Text(
|
// Text(
|
||||||
@ -43,8 +47,7 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!isKeyboardVisible)
|
if (!isKeyboardVisible) const HIHelpEntrance(),
|
||||||
const HIHelpEntrance(),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -76,30 +79,17 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final account = KRAppRunData.getInstance().kr_account.value;
|
final account = KRAppRunData.getInstance()
|
||||||
final isDeviceLogin = account != null && account.startsWith('9000');
|
.kr_account
|
||||||
|
.value;
|
||||||
if (isDeviceLogin) return const SizedBox();
|
final isDeviceLogin = account != null &&
|
||||||
|
account.startsWith('9000');
|
||||||
|
final accountText = isDeviceLogin
|
||||||
|
? '待绑定'
|
||||||
|
: 'ID: ${KRAppRunData.getInstance().kr_account.value.toString()}';
|
||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
account ?? '',
|
accountText,
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 20.sp,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
height: 0.9,
|
|
||||||
),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
Obx(() {
|
|
||||||
final _ = KRAppRunData.getInstance().kr_isLogin.value;
|
|
||||||
final userId = (KRAppRunData.getInstance().kr_userId.value ?? '').toString();
|
|
||||||
final deviceId = KRAppRunData.getInstance().deviceId ?? '';
|
|
||||||
|
|
||||||
return Text(
|
|
||||||
'ID: ${userId.isNotEmpty ? userId : deviceId}',
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white.withOpacity(0.85),
|
color: Colors.white.withOpacity(0.85),
|
||||||
fontSize: 14.sp,
|
fontSize: 14.sp,
|
||||||
@ -107,51 +97,14 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
Obx(() {
|
KRSubscriptionExpiryText(
|
||||||
final currentSubscribe =
|
expireTimeProvider: () => controller
|
||||||
controller.kr_subscribeService.kr_currentSubscribe.value;
|
.kr_subscribeService.kr_currentSubscribe.value?.expireTime,
|
||||||
String expiryText;
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
if (currentSubscribe == null) {
|
fontSize: 12.sp,
|
||||||
expiryText = '尚未购买套餐';
|
),
|
||||||
} else {
|
),
|
||||||
final now = DateTime.now();
|
|
||||||
DateTime? expireDateTime;
|
|
||||||
try {
|
|
||||||
expireDateTime =
|
|
||||||
DateTime.parse(currentSubscribe.expireTime);
|
|
||||||
} catch (e) {
|
|
||||||
expireDateTime = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expireDateTime == null) {
|
|
||||||
expiryText = '套餐信息无效';
|
|
||||||
} else if (expireDateTime.isBefore(now)) {
|
|
||||||
final formattedExpireDate =
|
|
||||||
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
|
||||||
expiryText = '已于 $formattedExpireDate 到期';
|
|
||||||
} else {
|
|
||||||
expiryText = '到期时间:${expireDateTime}';final year = expireDateTime.year;
|
|
||||||
final month = expireDateTime.month.toString().padLeft(2, '0');
|
|
||||||
final day = expireDateTime.day.toString().padLeft(2, '0');
|
|
||||||
final hour = expireDateTime.hour.toString().padLeft(2, '0');
|
|
||||||
final minute = expireDateTime.minute.toString().padLeft(2, '0');
|
|
||||||
final second = expireDateTime.second.toString().padLeft(2, '0');
|
|
||||||
|
|
||||||
// 2. 拼接成最终的字符串
|
|
||||||
final formattedDateTime = '$year/$month/$day $hour:$minute:$second';
|
|
||||||
|
|
||||||
expiryText = '到期时间:$formattedDateTime';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Text(
|
|
||||||
expiryText,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 12.sp,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -283,7 +236,8 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
color: const Color(0xFFA6A6A6),
|
color: const Color(0xFFA6A6A6),
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.w),
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.w),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(25.w), // 调整为更圆的角
|
borderRadius: BorderRadius.circular(25.w), // 调整为更圆的角
|
||||||
borderSide: BorderSide(color: Colors.white, width: 2),
|
borderSide: BorderSide(color: Colors.white, width: 2),
|
||||||
@ -327,7 +281,8 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
color: const Color(0xFFA6A6A6),
|
color: const Color(0xFFA6A6A6),
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.w),
|
contentPadding:
|
||||||
|
EdgeInsets.symmetric(horizontal: 16.w, vertical: 10.w),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(25.w),
|
borderRadius: BorderRadius.circular(25.w),
|
||||||
borderSide: BorderSide(color: Colors.white, width: 2),
|
borderSide: BorderSide(color: Colors.white, width: 2),
|
||||||
@ -347,14 +302,15 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
suffixIcon: Padding(
|
suffixIcon: Padding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
|
padding: EdgeInsets.symmetric(horizontal: 5.w, vertical: 5.w),
|
||||||
child: Obx(() {
|
child: Obx(() {
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: controller.kr_canSendCode.value ? () => controller.kr_sendCode() : null,
|
onTap: controller.kr_canSendCode.value
|
||||||
|
? () => controller.kr_sendCode()
|
||||||
|
: null,
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 100.w,
|
width: 100.w,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: controller.kr_canSendCode.value
|
color: controller.kr_canSendCode.value
|
||||||
? Theme.of(Get.context!).primaryColor
|
? Theme.of(Get.context!).primaryColor
|
||||||
: const Color(0xFFD5D5D5),
|
: const Color(0xFFD5D5D5),
|
||||||
borderRadius: BorderRadius.circular(100.r), // 药丸状
|
borderRadius: BorderRadius.circular(100.r), // 药丸状
|
||||||
@ -366,7 +322,7 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: controller.kr_canSendCode.value
|
color: controller.kr_canSendCode.value
|
||||||
? Colors.black
|
? Colors.black
|
||||||
: const Color(0xFF464655) ,
|
: const Color(0xFF464655),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -378,7 +334,6 @@ class KRLoginView extends GetView<KRLoginController> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget _buildSaveButton() {
|
Widget _buildSaveButton() {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
|||||||
67
lib/app/widgets/kr_subscription_expiry_text.dart
Normal file
67
lib/app/widgets/kr_subscription_expiry_text.dart
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class KRSubscriptionExpiryText extends StatelessWidget {
|
||||||
|
final String? Function() expireTimeProvider;
|
||||||
|
final TextStyle? style;
|
||||||
|
|
||||||
|
const KRSubscriptionExpiryText({
|
||||||
|
Key? key,
|
||||||
|
required this.expireTimeProvider,
|
||||||
|
this.style,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Obx(() {
|
||||||
|
final expireTimeStr = expireTimeProvider();
|
||||||
|
String expiryText;
|
||||||
|
bool highlight = false;
|
||||||
|
|
||||||
|
if (expireTimeStr == null || expireTimeStr.isEmpty) {
|
||||||
|
expiryText = '尚未购买套餐';
|
||||||
|
highlight = true;
|
||||||
|
} else {
|
||||||
|
DateTime? expireDateTime;
|
||||||
|
try {
|
||||||
|
expireDateTime = DateTime.parse(expireTimeStr);
|
||||||
|
} catch (_) {
|
||||||
|
expireDateTime = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expireDateTime == null) {
|
||||||
|
expiryText = '套餐信息无效';
|
||||||
|
} else if (expireDateTime.isBefore(DateTime.now())) {
|
||||||
|
final formattedExpireDate =
|
||||||
|
'${expireDateTime.year}/${expireDateTime.month.toString().padLeft(2, '0')}/${expireDateTime.day.toString().padLeft(2, '0')}';
|
||||||
|
expiryText = '已于 $formattedExpireDate 到期';
|
||||||
|
highlight = true;
|
||||||
|
} else {
|
||||||
|
final year = expireDateTime.year;
|
||||||
|
final month = expireDateTime.month.toString().padLeft(2, '0');
|
||||||
|
final day = expireDateTime.day.toString().padLeft(2, '0');
|
||||||
|
final hour = expireDateTime.hour.toString().padLeft(2, '0');
|
||||||
|
final minute = expireDateTime.minute.toString().padLeft(2, '0');
|
||||||
|
final second = expireDateTime.second.toString().padLeft(2, '0');
|
||||||
|
|
||||||
|
final formattedDateTime = '$year/$month/$day $hour:$minute:$second';
|
||||||
|
expiryText = '到期时间:$formattedDateTime';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final baseStyle = style ??
|
||||||
|
const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
);
|
||||||
|
final appliedStyle = highlight
|
||||||
|
? baseStyle.copyWith(color: const Color(0xFFFF00B7))
|
||||||
|
: baseStyle;
|
||||||
|
|
||||||
|
return Text(
|
||||||
|
expiryText,
|
||||||
|
style: appliedStyle,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user