| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696 |
- import 'package:flutter/material.dart';
- import 'package:flutter_screenutil/flutter_screenutil.dart';
- import 'package:get/get.dart';
- import 'package:nomo/config/theme/dark_theme_colors.dart';
- import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
- import 'package:shimmer/shimmer.dart';
- import 'package:video_player/video_player.dart';
- import '../../../../config/theme/light_theme_colors.dart';
- import '../../../../config/translations/strings_enum.dart';
- import '../../../constants/assets.dart';
- import '../../../widgets/info_card.dart';
- import '../../../widgets/ix_image.dart';
- import '../controllers/subscription_controller.dart';
- class SubscriptionView extends GetView<SubscriptionController> {
- const SubscriptionView({super.key});
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- backgroundColor: Get.reactiveTheme.scaffoldBackgroundColor,
- body: Stack(
- children: [
- // 视频背景层(只显示顶部214高度)
- Obx(() {
- if (controller.isVideoInitialized.value) {
- return Positioned(
- top: 0,
- left: 0,
- right: 0,
- height: 214.w,
- child: ClipRect(
- child: FittedBox(
- fit: BoxFit.cover,
- child: SizedBox(
- width: controller.videoController.value.size.width,
- height: controller.videoController.value.size.height,
- child: VideoPlayer(controller.videoController),
- ),
- ),
- ),
- );
- }
- return const SizedBox.shrink();
- }),
- // 渐变遮罩层(只在视频区域)
- Positioned(
- top: 0,
- left: 0,
- right: 0,
- height: 214.w,
- child: Container(
- decoration: BoxDecoration(
- gradient: LinearGradient(
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- colors: ReactiveTheme.isLightTheme
- ? [Colors.black, Color(0x99F5D89F), Color(0xFFEFF1F5)]
- : [Colors.black.withValues(alpha: 0.6), Colors.black],
- stops: ReactiveTheme.isLightTheme
- ? const [0.0, 0.7, 1.0]
- : const [0.0, 1.0],
- ),
- ),
- ),
- ),
- // 内容层
- SafeArea(
- child: Column(
- children: [
- _buildAppBar(),
- Expanded(
- child: SingleChildScrollView(
- padding: EdgeInsets.symmetric(horizontal: 20.w),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- 16.verticalSpaceFromWidth,
- _buildCurrentSubscription(),
- 24.verticalSpaceFromWidth,
- _buildPlanOptions(),
- // 仅 userLevel == 3 时显示套餐变更信息
- // if (controller.showPlanChangeInfo)
- // _buildPlanChangeInfo(),
- _buildPremiumFeatures(),
- 16.verticalSpaceFromWidth,
- ],
- ),
- ),
- ),
- _buildBottomSection(),
- ],
- ),
- ),
- ],
- ),
- );
- }
- // 顶部标题栏
- Widget _buildAppBar() {
- return Padding(
- padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 12.h),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- SizedBox(width: 32.w),
- Text(
- Strings.subscription.tr,
- style: TextStyle(
- fontSize: 16.sp,
- height: 1.4,
- fontWeight: FontWeight.w500,
- color: Colors.white,
- ),
- ),
- GestureDetector(
- onTap: () => Get.back(),
- child: Container(
- width: 24.w,
- height: 24.w,
- decoration: BoxDecoration(
- color: ReactiveTheme.isLightTheme
- ? LightThemeColors.strokes1
- : Color(0xFF333333),
- shape: BoxShape.circle,
- ),
- child: Icon(
- Icons.close_rounded,
- color: ReactiveTheme.isLightTheme
- ? LightThemeColors.text2
- : Colors.white,
- size: 16.w,
- ),
- ),
- ),
- ],
- ),
- );
- }
- // 当前订阅信息
- Widget _buildCurrentSubscription() {
- return Obx(() {
- // 判断是否有订阅
- if (!controller.hasCurrentSubscription) {
- // 没有订阅,只显示钻石图标
- return Center(
- child: IXImage(
- source: Assets.subscriptionDiamond,
- width: 92.w,
- height: 80.w,
- sourceType: ImageSourceType.asset,
- ),
- );
- }
- // 有订阅,显示当前套餐信息
- return Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- // 钻石图标
- IXImage(
- source: Assets.subscriptionDiamond,
- width: 92.w,
- height: 80.w,
- sourceType: ImageSourceType.asset,
- ),
- 12.horizontalSpace,
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- children: [
- IXImage(
- source: Assets.subscriptionWallet,
- width: 20.w,
- height: 20.w,
- sourceType: ImageSourceType.asset,
- ),
- 4.horizontalSpace,
- Text(
- Strings.currentSubscription.tr,
- style: TextStyle(
- fontSize: 14.sp,
- height: 1.4,
- color: ReactiveTheme.isLightTheme
- ? LightThemeColors.text1
- : DarkThemeColors.subscriptionColor,
- fontWeight: FontWeight.w700,
- ),
- ),
- ],
- ),
- 10.verticalSpaceFromWidth,
- Text(
- controller.currentPlanPriceDisplay,
- style: TextStyle(
- fontSize: 14.sp,
- height: 1.4,
- color: Get.reactiveTheme.textTheme.bodyLarge!.color,
- ),
- ),
- ],
- ),
- ),
- ],
- );
- });
- }
- // 订阅计划选项
- Widget _buildPlanOptions() {
- return Obx(() {
- // 加载中状态
- if (controller.isLoadingPlans.value) {
- return Column(
- children: List.generate(3, (index) => _buildPlanShimmer()),
- );
- }
- // 空数据状态
- if (controller.planCount == 0) {
- return Padding(
- padding: EdgeInsets.all(20.w),
- child: Center(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- crossAxisAlignment: CrossAxisAlignment.center,
- children: [
- Image.asset(Assets.oops, width: 170.w, height: 170.w),
- 10.verticalSpaceFromWidth,
- Text(
- Strings.oops.tr,
- style: TextStyle(
- fontSize: 22.sp,
- fontWeight: FontWeight.w400,
- height: 1.3,
- color: Get.reactiveTheme.textTheme.bodyLarge!.color,
- ),
- ),
- 4.verticalSpace,
- Padding(
- padding: EdgeInsets.symmetric(horizontal: 32.w),
- child: Text(
- Strings.connectionIssueDetected.tr,
- textAlign: TextAlign.center,
- style: TextStyle(
- fontSize: 14.sp,
- height: 1.4,
- color: Get.reactiveTheme.hintColor,
- ),
- ),
- ),
- ],
- ),
- ),
- );
- }
- // 套餐列表
- return Column(
- children: List.generate(
- controller.planCount,
- (index) => _buildPlanItem(index),
- ),
- );
- });
- }
- Widget _buildPlanShimmer() {
- final baseColor = ReactiveTheme.isLightTheme
- ? Colors.grey[300]!
- : Colors.grey[700]!;
- final highlightColor = ReactiveTheme.isLightTheme
- ? Colors.grey[100]!
- : Colors.grey[600]!;
- return Container(
- margin: EdgeInsets.only(bottom: 18.w),
- decoration: BoxDecoration(
- color: Get.reactiveTheme.cardColor,
- borderRadius: BorderRadius.circular(12.r),
- border: Border.all(color: Get.reactiveTheme.dividerColor, width: 2.w),
- ),
- child: Shimmer.fromColors(
- baseColor: baseColor,
- highlightColor: highlightColor,
- child: Padding(
- padding: EdgeInsets.all(10.w),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- // 左侧:模拟价格信息
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Container(
- width: 120.w,
- height: 18.w,
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(4.r),
- ),
- ),
- 8.verticalSpace,
- Container(
- width: 80.w,
- height: 14.w,
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(4.r),
- ),
- ),
- ],
- ),
- // 右侧:模拟标题
- Container(
- width: 60.w,
- height: 16.w,
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(4.r),
- ),
- ),
- ],
- ),
- ),
- ),
- );
- }
- Widget _buildPlanItem(int index) {
- return Obx(() {
- final isSelected = controller.selectedPlanIndex.value == index;
- final badge = controller.getPlanBadge(index);
- final badgeBgColor = controller.getPlanBadgeBgColor(index);
- final badgeTextColor = controller.getPlanBadgeTextColor(index);
- final badgeBorderColor = controller.getPlanBadgeBorderColor(index);
- return GestureDetector(
- onTap: () => controller.selectPlan(index),
- child: Container(
- margin: EdgeInsets.only(bottom: 18.w),
- decoration: BoxDecoration(
- color: Get.reactiveTheme.cardColor,
- borderRadius: BorderRadius.circular(12.r),
- border: Border.all(
- color: isSelected
- ? DarkThemeColors.subscriptionColor
- : Get.reactiveTheme.dividerColor,
- width: 2.w,
- ),
- ),
- child: Stack(
- clipBehavior: Clip.none,
- children: [
- // 主要内容
- Padding(
- padding: EdgeInsets.all(10.w),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- // 左侧:价格信息
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- controller.getPlanTitle(index),
- style: TextStyle(
- fontSize: 18.sp,
- height: 1.4,
- color:
- Get.reactiveTheme.textTheme.bodyLarge!.color,
- fontWeight: FontWeight.w600,
- ),
- ),
- Text(
- controller.getPlanSubTitle(index),
- style: TextStyle(
- fontSize: 12.sp,
- height: 1.6,
- color: Get.reactiveTheme.hintColor,
- ),
- ),
- ],
- ),
- ),
- // 右侧:标题和选择框
- Row(
- children: [
- Text(
- controller.getPlanIntroduce(index),
- style: TextStyle(
- fontSize: 13.sp,
- height: 1.4,
- color: Get.reactiveTheme.textTheme.bodyLarge!.color,
- ),
- ),
- // 8.horizontalSpace,
- // Container(
- // width: 20.w,
- // height: 20.w,
- // decoration: BoxDecoration(
- // shape: BoxShape.circle,
- // border: Border.all(
- // color: isSelected
- // ? DarkThemeColors.primaryColor
- // : ReactiveTheme.isLightTheme
- // ? LightThemeColors.strokes1
- // : Colors.white30,
- // width: 1.5.w,
- // ),
- // color: isSelected
- // ? DarkThemeColors.primaryColor
- // : Colors.transparent,
- // ),
- // child: isSelected
- // ? Icon(
- // Icons.check,
- // color: Colors.white,
- // size: 12.w,
- // )
- // : null,
- // ),
- ],
- ),
- ],
- ),
- ),
- // 标签固定在右上角,压在边框线上
- if (badge.isNotEmpty)
- Positioned(
- top: -11.h,
- right: 12.w,
- child: Container(
- padding: EdgeInsets.symmetric(horizontal: 6.w),
- decoration: BoxDecoration(
- color: badgeBgColor ?? Colors.black,
- borderRadius: BorderRadius.circular(4.r),
- border: badgeBorderColor != null
- ? Border.all(color: badgeBorderColor, width: 1)
- : null,
- ),
- child: Text(
- badge,
- style: TextStyle(
- fontSize: 12.sp,
- color: badgeTextColor ?? Colors.white,
- height: 1.6,
- ),
- ),
- ),
- ),
- ],
- ),
- ),
- );
- });
- }
- // 计划变更信息
- Widget _buildPlanChangeInfo() {
- return InfoCard(
- title: Strings.planChangeInfo.tr,
- items: [
- InfoItem(
- imageSource: Assets.subscriptionPlanChange1,
- title: Strings.whenItStarts.tr,
- description: Strings.yourNewPlanBeginsRightAway.tr,
- iconColor: DarkThemeColors.primaryColor,
- ),
- InfoItem(
- imageSource: Assets.subscriptionPlanChange2,
- title: Strings.whatHappensToYourBalance.tr,
- description: Strings.anyUnusedAmountFromYourOldPlan.tr,
- iconColor: DarkThemeColors.primaryColor,
- ),
- InfoItem(
- imageSource: Assets.subscriptionPlanChange3,
- title: Strings.extraTime.tr,
- description: Strings.youllGetExtraDays.tr,
- iconColor: DarkThemeColors.primaryColor,
- ),
- ],
- );
- }
- // Premium 功能列表
- Widget _buildPremiumFeatures() {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- Strings.premiumsIncluded.tr,
- style: TextStyle(
- fontSize: 16.sp,
- color: ReactiveTheme.isLightTheme
- ? LightThemeColors.primaryColor
- : DarkThemeColors.subscriptionColor,
- fontWeight: FontWeight.w500,
- ),
- ),
- 16.verticalSpace,
- Container(
- padding: EdgeInsets.symmetric(vertical: 4.w, horizontal: 10.w),
- decoration: BoxDecoration(
- color: Get.reactiveTheme.cardColor,
- borderRadius: BorderRadius.circular(12.r),
- ),
- child: Column(
- children: [
- Obx(
- () => _buildFeatureItem(
- Assets.equity1,
- Strings.equity1Title.trParams({
- 'count': controller.selectedPlanDeviceLimit,
- }),
- Strings.equity1Desc.trParams({
- 'count': controller.selectedPlanDeviceLimit,
- }),
- ),
- ),
- Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
- _buildFeatureItem(
- Assets.equity2,
- Strings.equity2Title.tr,
- Strings.equity2Desc.tr,
- ),
- Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
- _buildFeatureItem(
- Assets.equity3,
- Strings.equity3Title.tr,
- Strings.equity3Desc.tr,
- ),
- Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
- _buildFeatureItem(
- Assets.equity4,
- Strings.equity4Title.tr,
- Strings.equity4Desc.tr,
- ),
- Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
- _buildFeatureItem(
- Assets.equity5,
- Strings.equity5Title.tr,
- Strings.equity5Desc.tr,
- ),
- Divider(height: 1.w, color: Get.reactiveTheme.dividerColor),
- _buildFeatureItem(
- Assets.equity6,
- Strings.equity6Title.tr,
- Strings.equity6Desc.tr,
- ),
- ],
- ),
- ),
- ],
- );
- }
- Widget _buildFeatureItem(String imagePath, String title, String subtitle) {
- return Padding(
- padding: EdgeInsets.symmetric(vertical: 10.w),
- child: Row(
- children: [
- Image.asset(imagePath, width: 24.w, height: 24.w),
- 16.horizontalSpace,
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- title,
- style: TextStyle(
- fontSize: 14.sp,
- fontWeight: FontWeight.w500,
- color: Get.reactiveTheme.textTheme.bodyLarge!.color,
- ),
- ),
- 4.verticalSpace,
- Text(
- subtitle,
- style: TextStyle(
- fontSize: 12.sp,
- color: Get.reactiveTheme.hintColor,
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- );
- }
- // 底部按钮区域
- Widget _buildBottomSection() {
- return Container(
- padding: EdgeInsets.symmetric(vertical: 10.w, horizontal: 14.w),
- decoration: BoxDecoration(
- border: Border(
- top: BorderSide(color: Get.reactiveTheme.dividerColor, width: 1),
- ),
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- // 确认按钮
- GestureDetector(
- onTap: controller.subscribe,
- child: Container(
- width: double.infinity,
- height: 48.w,
- decoration: BoxDecoration(
- color: DarkThemeColors.backgroundColor,
- borderRadius: BorderRadius.circular(12.r),
- ),
- child: Center(
- child: Text(
- controller.showPlanChangeInfo
- ? Strings.confirmChange.tr
- : Strings.subscription.tr,
- style: TextStyle(
- fontSize: 16.sp,
- color: DarkThemeColors.subscriptionColor,
- fontWeight: FontWeight.w600,
- ),
- ),
- ),
- ),
- ),
- 14.verticalSpaceFromWidth,
- // 底部链接
- if (controller.apiController.fp.channel == 'google' ||
- controller.apiController.fp.channel == 'apple') ...[
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- GestureDetector(
- onTap: controller.restorePurchases,
- child: Text(
- Strings.restorePurchases.tr,
- style: TextStyle(
- fontSize: 16.sp,
- color: Get.reactiveTheme.textTheme.bodyLarge!.color,
- ),
- ),
- ),
- // Text(
- // ' | ',
- // style: TextStyle(
- // fontSize: 16.sp,
- // color: Get.reactiveTheme.hintColor,
- // ),
- // ),
- // GestureDetector(
- // onTap: controller.handlePaymentIssue,
- // child: Text(
- // Strings.paymentIssue.tr,
- // style: TextStyle(
- // fontSize: 16.sp,
- // color: Get.reactiveTheme.textTheme.bodyLarge!.color,
- // ),
- // ),
- // ),
- ],
- ),
- 14.verticalSpaceFromWidth,
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- IXImage(
- source: Assets.subscriptionGreenShield,
- width: 20.w,
- height: 20.w,
- sourceType: ImageSourceType.asset,
- ),
- 10.horizontalSpace,
- Text(
- Strings.yearlyAutoRenewCancelAnytime.tr,
- style: TextStyle(
- fontSize: 13.sp,
- color: Get.reactiveTheme.hintColor,
- ),
- ),
- ],
- ),
- ],
- ],
- ),
- );
- }
- }
|