From 9fc9b87608bebd2a45877b8200aec2a775471b1d Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Wed, 2 Jul 2025 22:17:25 +0800 Subject: [PATCH] :lipstick: Optimized leveling page --- assets/i18n/en-US.json | 25 ++--- assets/i18n/zh-CN.json | 10 +- lib/screens/account/leveling.dart | 127 ++++++++++++----------- lib/widgets/payment/payment_overlay.dart | 2 +- 4 files changed, 78 insertions(+), 86 deletions(-) diff --git a/assets/i18n/en-US.json b/assets/i18n/en-US.json index 2600eae..0dac724 100644 --- a/assets/i18n/en-US.json +++ b/assets/i18n/en-US.json @@ -46,7 +46,7 @@ "delete": "Delete", "deletePublisher": "Delete Publisher", "deletePublisherHint": "Are you sure to delete this publisher? This will also deleted all the post and collections under this publisher.", - "somethingWentWrong": "Something went wrong...", + "somethingWentWrong": "Something went wrong", "deletePost": "Delete Post", "safetyReport": "Report", "safetyReportTitle": "Safety Report", @@ -538,8 +538,6 @@ "paymentError": "Payment failed: {error}", "usePinInstead": "Use PIN Code", "levelProgress": "Level Progress", - "unlockedFeatures": "Unlocked Features", - "unlockedFeaturesDescription": "Features unlocked at your current level will be displayed here.", "stellarMembership": "Stellar Membership", "upgradeYourPlan": "Upgrade Your Plan", "chooseYourPlan": "Choose Your Plan", @@ -549,18 +547,9 @@ "membershipTierNova": "Nova", "membershipTierSupernova": "Supernova", "membershipTierUnknown": "Unknown", - "membershipPriceStellar": "10 NS$ per month", - "membershipPriceNova": "20 NS$ per month", - "membershipPriceSupernova": "30 NS$ per month", - "membershipFeatureBasic": "Basic features", - "membershipFeaturePrioritySupport": "Priority support", - "membershipFeatureAdFree": "Ad-free experience", - "membershipFeatureAllPrimary": "All Primary features", - "membershipFeatureAdvancedCustomization": "Advanced customization", - "membershipFeatureEarlyAccess": "Early access", - "membershipFeatureAllNova": "All Nova features", - "membershipFeatureExclusiveContent": "Exclusive content", - "membershipFeatureVipSupport": "VIP support", + "membershipPriceStellar": "1200 NSP per month, level 3+ required", + "membershipPriceNova": "2400 NSP per month, level 6+ required", + "membershipPriceSupernova": "3600 NSP per month, level 9+ required", "membershipCurrentBadge": "CURRENT", "restorePurchase": "Restore Purchase", "restorePurchaseDescription": "Enter your payment provider and order ID to restore your purchase.", @@ -678,5 +667,9 @@ "learnMore": "Learn More", "discoverWebArticles": "Articles from external sites", "webArticlesStand": "Article Stand", - "about": "About" + "about": "About", + "membershipCancel": "Cancel Membership", + "membershipCancelConfirm": "Are you sure to cancel your membership?", + "membershipCancelHint": "Are you sure to cancel your membership? You will not be charged again. Your membership will remain active until the end of the current billing period. And you will not able to resubscribe until the end of the current subscription ends.", + "membershipCancelSuccess": "Your membership has been successfully canceled." } \ No newline at end of file diff --git a/assets/i18n/zh-CN.json b/assets/i18n/zh-CN.json index 3565966..b49814d 100644 --- a/assets/i18n/zh-CN.json +++ b/assets/i18n/zh-CN.json @@ -46,7 +46,7 @@ "delete": "删除", "deletePublisher": "删除发布者", "deletePublisherHint": "确定要删除此发布者吗?这也会删除此发布者下的所有帖子和收藏。", - "somethingWentWrong": "发生了一些错误……", + "somethingWentWrong": "发生了一些错误", "deletePost": "删除帖子", "deletePostHint": "确定要删除这篇帖子吗?", "copyLink": "复制链接", @@ -490,8 +490,6 @@ "paymentError": "付款失败: {error}", "usePinInstead": "使用 PIN 码", "levelProgress": "等级进度", - "unlockedFeatures": "已解锁的功能", - "unlockedFeaturesDescription": "在您当前级别上解锁的功能将显示在这里。", "stellarMembership": "恒星计划", "upgradeYourPlan": "升级您的计划", "chooseYourPlan": "选择你的方案", @@ -501,9 +499,9 @@ "membershipTierNova": "新星", "membershipTierSupernova": "超新星", "membershipTierUnknown": "未知", - "membershipPriceStellar": "每月 10 金点", - "membershipPriceNova": "每月 20 金点", - "membershipPriceSupernova": "每月 30 金点", + "membershipPriceStellar": "每月 1200 源点,至少需要 3 级", + "membershipPriceNova": "每月 2400 源点,至少需要 6 级", + "membershipPriceSupernova": "每月 3600 源点,至少需要 9 级", "membershipFeatureBasic": "基础功能", "membershipFeaturePrioritySupport": "优先支持", "membershipFeatureAdFree": "无广告", diff --git a/lib/screens/account/leveling.dart b/lib/screens/account/leveling.dart index 9da4013..e60526d 100644 --- a/lib/screens/account/leveling.dart +++ b/lib/screens/account/leveling.dart @@ -1,4 +1,7 @@ +import 'dart:io'; + import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:google_fonts/google_fonts.dart'; @@ -14,7 +17,9 @@ import 'package:island/widgets/alert.dart'; import 'package:island/widgets/app_scaffold.dart'; import 'package:island/widgets/payment/payment_overlay.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:material_symbols_icons/symbols.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:styled_widget/styled_widget.dart'; part 'leveling.g.dart'; @@ -84,35 +89,6 @@ class LevelingScreen extends HookConsumerWidget { // Membership section _buildMembershipSection(context, ref, stellarSubscription), const Gap(16), - - // Unlocked features section - Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceContainerHigh, - borderRadius: BorderRadius.circular(12), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'unlockedFeatures'.tr(), - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - const Gap(8), - Text( - 'unlockedFeaturesDescription'.tr(), - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - ), - ], - ), - ), ], ), ), @@ -292,6 +268,31 @@ class LevelingScreen extends HookConsumerWidget { ) { final isActive = membership?.isActive ?? false; + Future membershipCancel() async { + if (!isActive || membership == null) return; + + final confirm = await showConfirmAlert( + 'membershipCancelHint'.tr(), + 'membershipCancelConfirm'.tr(), + ); + if (!confirm || !context.mounted) return; + + try { + showLoadingModal(context); + final client = ref.watch(apiClientProvider); + await client.post('/subscriptions/${membership.identifier}/cancel'); + ref.invalidate(accountStellarSubscriptionProvider); + ref.read(userInfoProvider.notifier).fetchUser(); + if (context.mounted) { + hideLoadingModal(context); + showSnackBar('membershipCancelSuccess'.tr()); + } + } catch (err) { + if (context.mounted) hideLoadingModal(context); + showErrorAlert(err); + } + } + return Container( width: double.infinity, padding: const EdgeInsets.all(16), @@ -307,7 +308,7 @@ class LevelingScreen extends HookConsumerWidget { borderRadius: BorderRadius.circular(12), ), child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( children: [ @@ -327,27 +328,42 @@ class LevelingScreen extends HookConsumerWidget { if (isActive) ...[ _buildCurrentMembershipCard(context, membership!), - const Gap(16), + const Gap(12), + FilledButton.icon( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + Theme.of(context).colorScheme.error, + ), + foregroundColor: WidgetStateProperty.all( + Theme.of(context).colorScheme.onError, + ), + ), + onPressed: membershipCancel, + icon: const Icon(Symbols.cancel), + label: Text('membershipCancel'.tr()), + ), ], - Text( - isActive ? 'upgradeYourPlan'.tr() : 'chooseYourPlan'.tr(), - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), - ), - const Gap(12), - - _buildMembershipTiers(context, ref, membership), - const Gap(12), + if (!isActive) ...[ + Text( + 'chooseYourPlan'.tr(), + style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), + ), + const Gap(12), + _buildMembershipTiers(context, ref, membership), + ], // Restore Purchase Button - OutlinedButton.icon( - onPressed: () => _showRestorePurchaseSheet(context, ref), - icon: const Icon(Icons.restore), - label: Text('restorePurchase'.tr()), - style: OutlinedButton.styleFrom( - minimumSize: const Size(double.infinity, 48), - ), - ), + // As you know Apple platform need IAP + if (kIsWeb || !(Platform.isIOS || Platform.isMacOS)) + OutlinedButton.icon( + onPressed: () => _showRestorePurchaseSheet(context, ref), + icon: const Icon(Icons.restore), + label: Text('restorePurchase'.tr()), + style: OutlinedButton.styleFrom( + minimumSize: const Size(double.infinity, 48), + ), + ).padding(top: 12), ], ), ); @@ -410,33 +426,18 @@ class LevelingScreen extends HookConsumerWidget { 'id': 'solian.stellar.primary', 'name': 'membershipTierStellar'.tr(), 'price': 'membershipPriceStellar'.tr(), - 'features': [ - 'membershipFeatureBasic'.tr(), - 'membershipFeaturePrioritySupport'.tr(), - 'membershipFeatureAdFree'.tr(), - ], 'color': Colors.blue, }, { 'id': 'solian.stellar.nova', 'name': 'membershipTierNova'.tr(), 'price': 'membershipPriceNova'.tr(), - 'features': [ - 'membershipFeatureAllPrimary'.tr(), - 'membershipFeatureAdvancedCustomization'.tr(), - 'membershipFeatureEarlyAccess'.tr(), - ], - 'color': Colors.purple, + 'color': Colors.indigo, }, { 'id': 'solian.stellar.supernova', 'name': 'membershipTierSupernova'.tr(), 'price': 'membershipPriceSupernova'.tr(), - 'features': [ - 'membershipFeatureAllNova'.tr(), - 'membershipFeatureExclusiveContent'.tr(), - 'membershipFeatureVipSupport'.tr(), - ], 'color': Colors.orange, }, ]; diff --git a/lib/widgets/payment/payment_overlay.dart b/lib/widgets/payment/payment_overlay.dart index 5b1fea4..71bf9e4 100644 --- a/lib/widgets/payment/payment_overlay.dart +++ b/lib/widgets/payment/payment_overlay.dart @@ -286,7 +286,7 @@ class _PaymentContentState extends ConsumerState<_PaymentContent> { } String _formatCurrency(int amount, String currency) { - final value = amount / 100.0; + final value = amount; return '${value.toStringAsFixed(2)} $currency'; }