| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- import 'package:flutter/material.dart';
- import 'package:flutter_screenutil/flutter_screenutil.dart';
- import 'package:get/get.dart';
- import 'package:nomo/app/constants/iconfont/iconfont.dart';
- import 'package:nomo/config/theme/dark_theme_colors.dart';
- import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
- import 'package:video_player/video_player.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: DarkThemeColors.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: [Colors.black.withValues(alpha: 0.6), Colors.black],
- stops: 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(),
- _buildPlanChangeInfo(),
- 16.verticalSpaceFromWidth,
- _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: Colors.white.withValues(alpha: 0.1),
- shape: BoxShape.circle,
- ),
- child: Icon(Icons.close_rounded, color: Colors.white, size: 16.w),
- ),
- ),
- ],
- ),
- );
- }
- // 当前订阅信息
- Widget _buildCurrentSubscription() {
- return Row(
- 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: DarkThemeColors.subscriptionColor,
- fontWeight: FontWeight.w700,
- ),
- ),
- ],
- ),
- 10.verticalSpaceFromWidth,
- Text(
- Strings.yearPlanPrice.trParams({'price': '\$40.00'}),
- style: TextStyle(
- fontSize: 14.sp,
- height: 1.4,
- color: Colors.white,
- ),
- ),
- ],
- ),
- ),
- ],
- );
- }
- // 订阅计划选项
- Widget _buildPlanOptions() {
- return Obx(
- () => Column(
- children: List.generate(
- controller.plans.length,
- (index) => _buildPlanItem(
- controller.plans[index],
- index,
- controller.selectedPlanIndex.value == index,
- ),
- ),
- ),
- );
- }
- Widget _buildPlanItem(Map<String, dynamic> plan, int index, bool isSelected) {
- final badge = plan['badge'] as String?;
- final badgeBgColor = plan['badgeBgColor'] as Color?;
- final badgeTextColor = plan['badgeTextColor'] as Color?;
- final badgeBorderColor = plan['badgeBorderColor'] as Color?;
- return GestureDetector(
- onTap: () => controller.selectPlan(index),
- child: Container(
- margin: EdgeInsets.only(bottom: 18.w),
- decoration: BoxDecoration(
- color: DarkThemeColors.cardColor,
- borderRadius: BorderRadius.circular(12.r),
- border: Border.all(
- color: isSelected
- ? DarkThemeColors.subscriptionColor
- : DarkThemeColors.dividerColor,
- width: 2.w,
- ),
- ),
- child: Stack(
- clipBehavior: Clip.none,
- children: [
- // 主要内容
- Padding(
- padding: EdgeInsets.all(10.w),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- plan['price'] as String,
- style: TextStyle(
- fontSize: 18.sp,
- height: 1.4,
- color: DarkThemeColors.bodyTextColor,
- fontWeight: FontWeight.w600,
- ),
- ),
- Text(
- plan['period'] as String,
- style: TextStyle(
- fontSize: 12.sp,
- height: 1.6,
- color: DarkThemeColors.hintTextColor,
- ),
- ),
- ],
- ),
- Row(
- children: [
- Text(
- plan['title'] as String,
- style: TextStyle(
- fontSize: 13.sp,
- height: 1.4,
- color: DarkThemeColors.bodyTextColor,
- ),
- ),
- 8.horizontalSpace,
- Container(
- width: 20.w,
- height: 20.w,
- decoration: BoxDecoration(
- shape: BoxShape.circle,
- border: Border.all(
- color: isSelected
- ? DarkThemeColors.primaryColor
- : 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 != null)
- 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: DarkThemeColors.subscriptionColor,
- fontWeight: FontWeight.w500,
- ),
- ),
- 16.verticalSpace,
- Container(
- padding: EdgeInsets.symmetric(vertical: 4.w, horizontal: 10.w),
- decoration: BoxDecoration(
- color: DarkThemeColors.bgDisable,
- borderRadius: BorderRadius.circular(12.r),
- ),
- child: Column(
- children: [
- _buildFeatureItem(
- IconFont.icon60,
- Strings.unlockAllFreeLocations.tr,
- ),
- _buildFeatureItem(IconFont.icon61, Strings.unlockSmartMode.tr),
- _buildFeatureItem(IconFont.icon62, Strings.unlockMultiHopMode.tr),
- _buildFeatureItem(
- IconFont.icon63,
- Strings.premiumCanShareXDevices.tr,
- ),
- _buildFeatureItem(
- IconFont.icon64,
- Strings.ownYourOwnPrivateServer.tr,
- ),
- _buildFeatureItem(IconFont.icon65, Strings.closeAds.tr),
- ],
- ),
- ),
- ],
- );
- }
- Widget _buildFeatureItem(IconData icon, String title) {
- return SizedBox(
- height: 44.w,
- child: Row(
- children: [
- Icon(icon, color: DarkThemeColors.subscriptionColor, size: 24.w),
- 12.horizontalSpace,
- Expanded(
- child: Text(
- title,
- style: TextStyle(
- fontSize: 13.sp,
- color: Get.reactiveTheme.hintColor,
- ),
- ),
- ),
- Container(
- width: 20.w,
- height: 20.w,
- decoration: BoxDecoration(
- shape: BoxShape.circle,
- color: DarkThemeColors.subscriptionSelectColor,
- ),
- child: Icon(Icons.check, color: Colors.white, size: 12.w),
- ),
- ],
- ),
- );
- }
- // 底部按钮区域
- Widget _buildBottomSection() {
- return Container(
- padding: EdgeInsets.symmetric(vertical: 10.w, horizontal: 14.w),
- decoration: BoxDecoration(
- border: Border(
- top: BorderSide(color: Colors.white.withOpacity(0.1), width: 1),
- ),
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- // 确认按钮
- GestureDetector(
- onTap: controller.confirmChange,
- child: Container(
- width: double.infinity,
- height: 48.h,
- decoration: BoxDecoration(
- color: DarkThemeColors.backgroundColor,
- borderRadius: BorderRadius.circular(12.r),
- ),
- child: Center(
- child: Text(
- Strings.confirmChange.tr,
- style: TextStyle(
- fontSize: 16.sp,
- color: DarkThemeColors.subscriptionColor,
- fontWeight: FontWeight.w600,
- ),
- ),
- ),
- ),
- ),
- 14.verticalSpaceFromWidth,
- // 底部链接
- Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- GestureDetector(
- onTap: controller.restorePurchases,
- child: Text(
- Strings.restorePurchases.tr,
- style: TextStyle(
- fontSize: 16.sp,
- color: DarkThemeColors.bodyTextColor,
- ),
- ),
- ),
- Text(
- ' | ',
- style: TextStyle(
- fontSize: 16.sp,
- color: DarkThemeColors.hintTextColor,
- ),
- ),
- GestureDetector(
- onTap: controller.handlePaymentIssue,
- child: Text(
- Strings.paymentIssue.tr,
- style: TextStyle(
- fontSize: 16.sp,
- color: DarkThemeColors.bodyTextColor,
- ),
- ),
- ),
- ],
- ),
- 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: DarkThemeColors.hintTextColor,
- ),
- ),
- ],
- ),
- ],
- ),
- );
- }
- }
|