Compare commits
4 Commits
d414695eb3
...
13ea182707
Author | SHA1 | Date | |
---|---|---|---|
13ea182707 | |||
14183a7316 | |||
9fc9b87608 | |||
53c2445ba9 |
@ -46,7 +46,7 @@
|
|||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"deletePublisher": "Delete Publisher",
|
"deletePublisher": "Delete Publisher",
|
||||||
"deletePublisherHint": "Are you sure to delete this publisher? This will also deleted all the post and collections under this 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",
|
"deletePost": "Delete Post",
|
||||||
"safetyReport": "Report",
|
"safetyReport": "Report",
|
||||||
"safetyReportTitle": "Safety Report",
|
"safetyReportTitle": "Safety Report",
|
||||||
@ -538,29 +538,19 @@
|
|||||||
"paymentError": "Payment failed: {error}",
|
"paymentError": "Payment failed: {error}",
|
||||||
"usePinInstead": "Use PIN Code",
|
"usePinInstead": "Use PIN Code",
|
||||||
"levelProgress": "Level Progress",
|
"levelProgress": "Level Progress",
|
||||||
"unlockedFeatures": "Unlocked Features",
|
|
||||||
"unlockedFeaturesDescription": "Features unlocked at your current level will be displayed here.",
|
|
||||||
"stellarMembership": "Stellar Membership",
|
"stellarMembership": "Stellar Membership",
|
||||||
"upgradeYourPlan": "Upgrade Your Plan",
|
"upgradeYourPlan": "Upgrade Your Plan",
|
||||||
"chooseYourPlan": "Choose Your Plan",
|
"chooseYourPlan": "Choose Your Plan",
|
||||||
"currentMembership": "Current: {}",
|
"currentMembership": "Current: {}",
|
||||||
|
"currentMembershipMember": "A member of Stellar Program · {}",
|
||||||
"membershipExpires": "Expires: {}",
|
"membershipExpires": "Expires: {}",
|
||||||
"membershipTierStellar": "Stellar",
|
"membershipTierStellar": "Stellar",
|
||||||
"membershipTierNova": "Nova",
|
"membershipTierNova": "Nova",
|
||||||
"membershipTierSupernova": "Supernova",
|
"membershipTierSupernova": "Supernova",
|
||||||
"membershipTierUnknown": "Unknown",
|
"membershipTierUnknown": "Unknown",
|
||||||
"membershipPriceStellar": "10 NS$ per month",
|
"membershipPriceStellar": "1200 NSP per month, level 3+ required",
|
||||||
"membershipPriceNova": "20 NS$ per month",
|
"membershipPriceNova": "2400 NSP per month, level 6+ required",
|
||||||
"membershipPriceSupernova": "30 NS$ per month",
|
"membershipPriceSupernova": "3600 NSP per month, level 9+ required",
|
||||||
"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",
|
|
||||||
"membershipCurrentBadge": "CURRENT",
|
"membershipCurrentBadge": "CURRENT",
|
||||||
"restorePurchase": "Restore Purchase",
|
"restorePurchase": "Restore Purchase",
|
||||||
"restorePurchaseDescription": "Enter your payment provider and order ID to restore your purchase.",
|
"restorePurchaseDescription": "Enter your payment provider and order ID to restore your purchase.",
|
||||||
@ -597,7 +587,7 @@
|
|||||||
"no": "No",
|
"no": "No",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"navigateToChat": "Navigate to Chat",
|
"navigateToChat": "Navigate to Chat",
|
||||||
"wouldYouLikeToNavigateToChat": "Would you like to navigate to the chat?",
|
"wouldYouLikeToNavigateToChat": "Would You like to navigate to the chat?",
|
||||||
"abuseReport": "Report",
|
"abuseReport": "Report",
|
||||||
"abuseReportTitle": "Report Content",
|
"abuseReportTitle": "Report Content",
|
||||||
"abuseReportDescription": "Help us keep the community safe by reporting inappropriate content or behavior.",
|
"abuseReportDescription": "Help us keep the community safe by reporting inappropriate content or behavior.",
|
||||||
@ -678,5 +668,27 @@
|
|||||||
"learnMore": "Learn More",
|
"learnMore": "Learn More",
|
||||||
"discoverWebArticles": "Articles from external sites",
|
"discoverWebArticles": "Articles from external sites",
|
||||||
"webArticlesStand": "Article Stand",
|
"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.",
|
||||||
|
"aboutScreenTitle": "About",
|
||||||
|
"aboutScreenVersionInfo": "Version {} ({})",
|
||||||
|
"aboutScreenAppInfoSectionTitle": "App Information",
|
||||||
|
"aboutScreenPackageNameLabel": "Package Name",
|
||||||
|
"aboutScreenVersionLabel": "Version",
|
||||||
|
"aboutScreenBuildNumberLabel": "Build Number",
|
||||||
|
"aboutScreenLinksSectionTitle": "Links",
|
||||||
|
"aboutScreenPrivacyPolicyTitle": "Privacy Policy",
|
||||||
|
"aboutScreenTermsOfServiceTitle": "Terms of Service",
|
||||||
|
"aboutScreenOpenSourceLicensesTitle": "Open Source Licenses",
|
||||||
|
"aboutScreenDeveloperSectionTitle": "Developer",
|
||||||
|
"aboutScreenContactUsTitle": "Contact Us",
|
||||||
|
"aboutScreenLicenseTitle": "License",
|
||||||
|
"aboutScreenLicenseContent": "All copyright reserved © {} Solsynth\nOpen-sourced under license GNU AGPL v3.0",
|
||||||
|
"aboutScreenCopyright": "© {} {}. All rights reserved.",
|
||||||
|
"aboutScreenFailedToLoadPackageInfo": "Failed to load package info: {error}",
|
||||||
|
"copiedToClipboard": "Copied to clipboard",
|
||||||
|
"copyToClipboardTooltip": "Copy to clipboard"
|
||||||
}
|
}
|
@ -46,7 +46,7 @@
|
|||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
"deletePublisher": "删除发布者",
|
"deletePublisher": "删除发布者",
|
||||||
"deletePublisherHint": "确定要删除此发布者吗?这也会删除此发布者下的所有帖子和收藏。",
|
"deletePublisherHint": "确定要删除此发布者吗?这也会删除此发布者下的所有帖子和收藏。",
|
||||||
"somethingWentWrong": "发生了一些错误……",
|
"somethingWentWrong": "发生了一些错误",
|
||||||
"deletePost": "删除帖子",
|
"deletePost": "删除帖子",
|
||||||
"deletePostHint": "确定要删除这篇帖子吗?",
|
"deletePostHint": "确定要删除这篇帖子吗?",
|
||||||
"copyLink": "复制链接",
|
"copyLink": "复制链接",
|
||||||
@ -345,7 +345,7 @@
|
|||||||
"accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。",
|
"accountSettingsHelpContent": "此页面允许您管理您的帐户安全性、隐私和其他设置。如果您需要帮助,请联系管理员。",
|
||||||
"unauthorized": "未授权",
|
"unauthorized": "未授权",
|
||||||
"unauthorizedHint": "您未登录或会话已过期,请重新登录。",
|
"unauthorizedHint": "您未登录或会话已过期,请重新登录。",
|
||||||
"publisherBelongsTo": "属于",
|
"publisherBelongsTo": "属于 {}",
|
||||||
"postContent": "内容",
|
"postContent": "内容",
|
||||||
"postSettings": "设置",
|
"postSettings": "设置",
|
||||||
"postPublisherUnselected": "未指定发布者",
|
"postPublisherUnselected": "未指定发布者",
|
||||||
@ -490,29 +490,20 @@
|
|||||||
"paymentError": "付款失败: {error}",
|
"paymentError": "付款失败: {error}",
|
||||||
"usePinInstead": "使用 PIN 码",
|
"usePinInstead": "使用 PIN 码",
|
||||||
"levelProgress": "等级进度",
|
"levelProgress": "等级进度",
|
||||||
"unlockedFeatures": "已解锁的功能",
|
|
||||||
"unlockedFeaturesDescription": "在您当前级别上解锁的功能将显示在这里。",
|
|
||||||
"stellarMembership": "恒星计划",
|
"stellarMembership": "恒星计划",
|
||||||
"upgradeYourPlan": "升级您的计划",
|
"upgradeYourPlan": "升级您的计划",
|
||||||
"chooseYourPlan": "选择你的方案",
|
"chooseYourPlan": "选择你的方案",
|
||||||
"currentMembership": "当前:{}",
|
"currentMembership": "当前:{}",
|
||||||
|
"currentMembershipMember": "恒星计划「{}」级会员",
|
||||||
"membershipExpires": "过期于:{}",
|
"membershipExpires": "过期于:{}",
|
||||||
"membershipTierStellar": "恒星",
|
"membershipTierStellar": "恒星",
|
||||||
"membershipTierNova": "新星",
|
"membershipTierNova": "新星",
|
||||||
"membershipTierSupernova": "超新星",
|
"membershipTierSupernova": "超新星",
|
||||||
"membershipTierUnknown": "未知",
|
"membershipTierUnknown": "未知",
|
||||||
"membershipPriceStellar": "每月 10 金点",
|
"membershipPriceStellar": "每月 1200 源点,至少需要 3 级",
|
||||||
"membershipPriceNova": "每月 20 金点",
|
"membershipPriceNova": "每月 2400 源点,至少需要 6 级",
|
||||||
"membershipPriceSupernova": "每月 30 金点",
|
"membershipPriceSupernova": "每月 3600 源点,至少需要 9 级",
|
||||||
"membershipFeatureBasic": "基础功能",
|
"membershipFeatureBasic": "基础功能",
|
||||||
"membershipFeaturePrioritySupport": "优先支持",
|
|
||||||
"membershipFeatureAdFree": "无广告",
|
|
||||||
"membershipFeatureAllPrimary": "所有主要功能",
|
|
||||||
"membershipFeatureAdvancedCustomization": "高级自定义",
|
|
||||||
"membershipFeatureEarlyAccess": "抢先体验",
|
|
||||||
"membershipFeatureAllNova": "所有「新星」功能",
|
|
||||||
"membershipFeatureExclusiveContent": "限定内容",
|
|
||||||
"membershipFeatureVipSupport": "VIP 支持",
|
|
||||||
"membershipCurrentBadge": "当前",
|
"membershipCurrentBadge": "当前",
|
||||||
"restorePurchase": "恢复购买",
|
"restorePurchase": "恢复购买",
|
||||||
"restorePurchaseDescription": "输入您付款的提供商和订单 ID 以恢复您的购买。",
|
"restorePurchaseDescription": "输入您付款的提供商和订单 ID 以恢复您的购买。",
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
|
||||||
class AboutScreen extends StatefulWidget {
|
class AboutScreen extends StatefulWidget {
|
||||||
const AboutScreen({super.key});
|
const AboutScreen({super.key});
|
||||||
@ -12,8 +14,8 @@ class AboutScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _AboutScreenState extends State<AboutScreen> {
|
class _AboutScreenState extends State<AboutScreen> {
|
||||||
PackageInfo _packageInfo = PackageInfo(
|
PackageInfo _packageInfo = PackageInfo(
|
||||||
appName: 'Island',
|
appName: 'Solian',
|
||||||
packageName: 'com.example.island',
|
packageName: 'dev.solsynth.solian',
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
buildNumber: '1',
|
buildNumber: '1',
|
||||||
);
|
);
|
||||||
@ -38,7 +40,9 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_errorMessage = 'Failed to load package info: $e';
|
_errorMessage = 'aboutScreenFailedToLoadPackageInfo'.tr(
|
||||||
|
args: [e.toString()],
|
||||||
|
);
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -57,7 +61,7 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('About'), elevation: 0),
|
appBar: AppBar(title: Text('about'.tr()), elevation: 0),
|
||||||
body:
|
body:
|
||||||
_isLoading
|
_isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
@ -88,7 +92,9 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'Version ${_packageInfo.version} (${_packageInfo.buildNumber})',
|
'aboutScreenVersionInfo'.tr(
|
||||||
|
args: [_packageInfo.version, _packageInfo.buildNumber],
|
||||||
|
),
|
||||||
style: theme.textTheme.bodyMedium?.copyWith(
|
style: theme.textTheme.bodyMedium?.copyWith(
|
||||||
color: theme.textTheme.bodySmall?.color,
|
color: theme.textTheme.bodySmall?.color,
|
||||||
),
|
),
|
||||||
@ -98,24 +104,24 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
// App Info Card
|
// App Info Card
|
||||||
_buildSection(
|
_buildSection(
|
||||||
context,
|
context,
|
||||||
title: 'App Information',
|
title: 'aboutScreenAppInfoSectionTitle'.tr(),
|
||||||
children: [
|
children: [
|
||||||
_buildInfoItem(
|
_buildInfoItem(
|
||||||
context,
|
context,
|
||||||
icon: Icons.info_outline,
|
icon: Icons.info_outline,
|
||||||
label: 'Package Name',
|
label: 'aboutScreenPackageNameLabel'.tr(),
|
||||||
value: _packageInfo.packageName,
|
value: _packageInfo.packageName,
|
||||||
),
|
),
|
||||||
_buildInfoItem(
|
_buildInfoItem(
|
||||||
context,
|
context,
|
||||||
icon: Icons.update,
|
icon: Icons.update,
|
||||||
label: 'Version',
|
label: 'aboutScreenVersionLabel'.tr(),
|
||||||
value: _packageInfo.version,
|
value: _packageInfo.version,
|
||||||
),
|
),
|
||||||
_buildInfoItem(
|
_buildInfoItem(
|
||||||
context,
|
context,
|
||||||
icon: Icons.build,
|
icon: Icons.build,
|
||||||
label: 'Build Number',
|
label: 'aboutScreenBuildNumberLabel'.tr(),
|
||||||
value: _packageInfo.buildNumber,
|
value: _packageInfo.buildNumber,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -126,12 +132,12 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
// Links Card
|
// Links Card
|
||||||
_buildSection(
|
_buildSection(
|
||||||
context,
|
context,
|
||||||
title: 'Links',
|
title: 'aboutScreenLinksSectionTitle'.tr(),
|
||||||
children: [
|
children: [
|
||||||
_buildListTile(
|
_buildListTile(
|
||||||
context,
|
context,
|
||||||
icon: Icons.privacy_tip_outlined,
|
icon: Icons.privacy_tip_outlined,
|
||||||
title: 'Privacy Policy',
|
title: 'aboutScreenPrivacyPolicyTitle'.tr(),
|
||||||
onTap:
|
onTap:
|
||||||
() => _launchURL(
|
() => _launchURL(
|
||||||
'https://solsynth.dev/terms/privacy-policy',
|
'https://solsynth.dev/terms/privacy-policy',
|
||||||
@ -140,16 +146,16 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
_buildListTile(
|
_buildListTile(
|
||||||
context,
|
context,
|
||||||
icon: Icons.description_outlined,
|
icon: Icons.description_outlined,
|
||||||
title: 'Terms of Service',
|
title: 'aboutScreenTermsOfServiceTitle'.tr(),
|
||||||
onTap:
|
onTap:
|
||||||
() => _launchURL(
|
() => _launchURL(
|
||||||
'https://example.com/terms/basic-law',
|
'https://solsynth.dev/terms/basic-law',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_buildListTile(
|
_buildListTile(
|
||||||
context,
|
context,
|
||||||
icon: Icons.code,
|
icon: Icons.code,
|
||||||
title: 'Open Source Licenses',
|
title: 'aboutScreenOpenSourceLicensesTitle'.tr(),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showLicensePage(
|
showLicensePage(
|
||||||
context: context,
|
context: context,
|
||||||
@ -167,21 +173,22 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
// Developer Info
|
// Developer Info
|
||||||
_buildSection(
|
_buildSection(
|
||||||
context,
|
context,
|
||||||
title: 'Developer',
|
title: 'aboutScreenDeveloperSectionTitle'.tr(),
|
||||||
children: [
|
children: [
|
||||||
_buildListTile(
|
_buildListTile(
|
||||||
context,
|
context,
|
||||||
icon: Icons.email_outlined,
|
icon: Icons.email_outlined,
|
||||||
title: 'Contact Us',
|
title: 'aboutScreenContactUsTitle'.tr(),
|
||||||
subtitle: 'lily@solsynth.dev',
|
subtitle: 'lily@solsynth.dev',
|
||||||
onTap: () => _launchURL('mailto:lily@solsynth.dev'),
|
onTap: () => _launchURL('mailto:lily@solsynth.dev'),
|
||||||
),
|
),
|
||||||
_buildListTile(
|
_buildListTile(
|
||||||
context,
|
context,
|
||||||
icon: Icons.copyright,
|
icon: Icons.copyright,
|
||||||
title: 'License',
|
title: 'aboutScreenLicenseTitle'.tr(),
|
||||||
subtitle:
|
subtitle: 'aboutScreenLicenseContent'.tr(
|
||||||
'Copyright reserved © ${DateTime.now().year} Solsynth\nGNU Affero General Public License v3.0',
|
args: [DateTime.now().year.toString()],
|
||||||
|
),
|
||||||
onTap:
|
onTap:
|
||||||
() => _launchURL(
|
() => _launchURL(
|
||||||
'https://github.com/Solsynth/Solian/blob/v3/LICENSE.txt',
|
'https://github.com/Solsynth/Solian/blob/v3/LICENSE.txt',
|
||||||
@ -196,7 +203,9 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
'© ${DateTime.now().year} ${_packageInfo.appName}. All rights reserved.',
|
'aboutScreenCopyright'.tr(
|
||||||
|
args: [DateTime.now().year.toString(), "Solsynth"],
|
||||||
|
),
|
||||||
style: theme.textTheme.bodySmall,
|
style: theme.textTheme.bodySmall,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
@ -264,12 +273,12 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
Clipboard.setData(ClipboardData(text: value));
|
Clipboard.setData(ClipboardData(text: value));
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Copied to clipboard')),
|
SnackBar(content: Text('copiedToClipboard'.tr())),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints(),
|
constraints: const BoxConstraints(),
|
||||||
tooltip: 'Copy to clipboard',
|
tooltip: 'copyToClipboardTooltip'.tr(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -283,13 +292,18 @@ class _AboutScreenState extends State<AboutScreen> {
|
|||||||
String? subtitle,
|
String? subtitle,
|
||||||
required VoidCallback onTap,
|
required VoidCallback onTap,
|
||||||
}) {
|
}) {
|
||||||
|
final multipleLines = subtitle?.contains('\n') ?? false;
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(icon),
|
leading: Icon(icon).padding(top: multipleLines ? 8 : 0),
|
||||||
title: Text(title),
|
title: Text(title),
|
||||||
subtitle: subtitle != null ? Text(subtitle) : null,
|
subtitle: subtitle != null ? Text(subtitle) : null,
|
||||||
trailing: const Icon(Icons.chevron_right),
|
isThreeLine: multipleLines,
|
||||||
|
trailing: const Icon(
|
||||||
|
Icons.chevron_right,
|
||||||
|
).padding(top: multipleLines ? 8 : 0),
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
minLeadingWidth: 24,
|
minLeadingWidth: 24,
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:google_fonts/google_fonts.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/app_scaffold.dart';
|
||||||
import 'package:island/widgets/payment/payment_overlay.dart';
|
import 'package:island/widgets/payment/payment_overlay.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
part 'leveling.g.dart';
|
part 'leveling.g.dart';
|
||||||
|
|
||||||
@ -84,35 +89,6 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
// Membership section
|
// Membership section
|
||||||
_buildMembershipSection(context, ref, stellarSubscription),
|
_buildMembershipSection(context, ref, stellarSubscription),
|
||||||
const Gap(16),
|
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;
|
final isActive = membership?.isActive ?? false;
|
||||||
|
|
||||||
|
Future<void> 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(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
@ -307,7 +308,7 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@ -327,19 +328,34 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
if (isActive) ...[
|
if (isActive) ...[
|
||||||
_buildCurrentMembershipCard(context, membership!),
|
_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()),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
if (!isActive) ...[
|
||||||
Text(
|
Text(
|
||||||
isActive ? 'upgradeYourPlan'.tr() : 'chooseYourPlan'.tr(),
|
'chooseYourPlan'.tr(),
|
||||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
const Gap(12),
|
const Gap(12),
|
||||||
|
|
||||||
_buildMembershipTiers(context, ref, membership),
|
_buildMembershipTiers(context, ref, membership),
|
||||||
const Gap(12),
|
],
|
||||||
|
|
||||||
// Restore Purchase Button
|
// Restore Purchase Button
|
||||||
|
// As you know Apple platform need IAP
|
||||||
|
if (kIsWeb || !(Platform.isIOS || Platform.isMacOS))
|
||||||
OutlinedButton.icon(
|
OutlinedButton.icon(
|
||||||
onPressed: () => _showRestorePurchaseSheet(context, ref),
|
onPressed: () => _showRestorePurchaseSheet(context, ref),
|
||||||
icon: const Icon(Icons.restore),
|
icon: const Icon(Icons.restore),
|
||||||
@ -347,7 +363,7 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
style: OutlinedButton.styleFrom(
|
style: OutlinedButton.styleFrom(
|
||||||
minimumSize: const Size(double.infinity, 48),
|
minimumSize: const Size(double.infinity, 48),
|
||||||
),
|
),
|
||||||
),
|
).padding(top: 12),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -410,33 +426,18 @@ class LevelingScreen extends HookConsumerWidget {
|
|||||||
'id': 'solian.stellar.primary',
|
'id': 'solian.stellar.primary',
|
||||||
'name': 'membershipTierStellar'.tr(),
|
'name': 'membershipTierStellar'.tr(),
|
||||||
'price': 'membershipPriceStellar'.tr(),
|
'price': 'membershipPriceStellar'.tr(),
|
||||||
'features': [
|
|
||||||
'membershipFeatureBasic'.tr(),
|
|
||||||
'membershipFeaturePrioritySupport'.tr(),
|
|
||||||
'membershipFeatureAdFree'.tr(),
|
|
||||||
],
|
|
||||||
'color': Colors.blue,
|
'color': Colors.blue,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'solian.stellar.nova',
|
'id': 'solian.stellar.nova',
|
||||||
'name': 'membershipTierNova'.tr(),
|
'name': 'membershipTierNova'.tr(),
|
||||||
'price': 'membershipPriceNova'.tr(),
|
'price': 'membershipPriceNova'.tr(),
|
||||||
'features': [
|
'color': Colors.indigo,
|
||||||
'membershipFeatureAllPrimary'.tr(),
|
|
||||||
'membershipFeatureAdvancedCustomization'.tr(),
|
|
||||||
'membershipFeatureEarlyAccess'.tr(),
|
|
||||||
],
|
|
||||||
'color': Colors.purple,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 'solian.stellar.supernova',
|
'id': 'solian.stellar.supernova',
|
||||||
'name': 'membershipTierSupernova'.tr(),
|
'name': 'membershipTierSupernova'.tr(),
|
||||||
'price': 'membershipPriceSupernova'.tr(),
|
'price': 'membershipPriceSupernova'.tr(),
|
||||||
'features': [
|
|
||||||
'membershipFeatureAllNova'.tr(),
|
|
||||||
'membershipFeatureExclusiveContent'.tr(),
|
|
||||||
'membershipFeatureVipSupport'.tr(),
|
|
||||||
],
|
|
||||||
'color': Colors.orange,
|
'color': Colors.orange,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -9,7 +9,6 @@ import 'package:island/widgets/app_scaffold.dart';
|
|||||||
import 'package:island/widgets/post/post_item.dart';
|
import 'package:island/widgets/post/post_item.dart';
|
||||||
import 'package:island/widgets/post/post_quick_reply.dart';
|
import 'package:island/widgets/post/post_quick_reply.dart';
|
||||||
import 'package:island/widgets/post/post_replies.dart';
|
import 'package:island/widgets/post/post_replies.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
|
@ -341,26 +341,6 @@ class SettingsScreen extends HookConsumerWidget {
|
|||||||
];
|
];
|
||||||
|
|
||||||
final behaviorSettings = [
|
final behaviorSettings = [
|
||||||
ListTile(
|
|
||||||
minLeadingWidth: 48,
|
|
||||||
title: Text('creatorHub').tr(),
|
|
||||||
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
|
||||||
leading: const Icon(Symbols.rocket_launch),
|
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
|
||||||
onTap: () => context.push('/creators'),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Developer Hub
|
|
||||||
ListTile(
|
|
||||||
minLeadingWidth: 48,
|
|
||||||
title: Text('developerHub').tr(),
|
|
||||||
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
|
||||||
leading: const Icon(Symbols.hub),
|
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
|
||||||
onTap: () => context.push('/developers'),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Auto translate settings
|
|
||||||
ListTile(
|
ListTile(
|
||||||
minLeadingWidth: 48,
|
minLeadingWidth: 48,
|
||||||
title: Text('settingsAutoTranslate').tr(),
|
title: Text('settingsAutoTranslate').tr(),
|
||||||
|
@ -21,11 +21,23 @@ class AccountName extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
var nameStyle = (style ?? TextStyle());
|
||||||
|
if (account.profile.stellarMembership != null) {
|
||||||
|
nameStyle = nameStyle.copyWith(
|
||||||
|
color: (switch (account.profile.stellarMembership!.identifier) {
|
||||||
|
'solian.stellar.primary' => Colors.blueAccent,
|
||||||
|
'solian.stellar.nova' => Colors.indigoAccent,
|
||||||
|
'solian.stellar.supernova' => Colors.amberAccent,
|
||||||
|
_ => null,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
spacing: 4,
|
spacing: 4,
|
||||||
children: [
|
children: [
|
||||||
Flexible(child: Text(account.nick, style: style)),
|
Flexible(child: Text(account.nick, style: nameStyle)),
|
||||||
if (account.profile.stellarMembership != null)
|
if (account.profile.stellarMembership != null)
|
||||||
StellarMembershipMark(membership: account.profile.stellarMembership!),
|
StellarMembershipMark(membership: account.profile.stellarMembership!),
|
||||||
if (account.profile.verification != null)
|
if (account.profile.verification != null)
|
||||||
@ -87,36 +99,23 @@ class StellarMembershipMark extends StatelessWidget {
|
|||||||
Color _getMembershipTierColor(String identifier) {
|
Color _getMembershipTierColor(String identifier) {
|
||||||
switch (identifier) {
|
switch (identifier) {
|
||||||
case 'solian.stellar.primary':
|
case 'solian.stellar.primary':
|
||||||
return Colors.amber;
|
|
||||||
case 'solian.stellar.nova':
|
|
||||||
return Colors.blue;
|
return Colors.blue;
|
||||||
|
case 'solian.stellar.nova':
|
||||||
|
return Colors.indigo;
|
||||||
case 'solian.stellar.supernova':
|
case 'solian.stellar.supernova':
|
||||||
return Colors.purple;
|
return Colors.amber;
|
||||||
default:
|
default:
|
||||||
return Colors.grey;
|
return Colors.grey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IconData _getMembershipTierIcon(String identifier) {
|
|
||||||
switch (identifier) {
|
|
||||||
case 'solian.stellar.primary':
|
|
||||||
return Symbols.star;
|
|
||||||
case 'solian.stellar.nova':
|
|
||||||
return Symbols.auto_awesome;
|
|
||||||
case 'solian.stellar.supernova':
|
|
||||||
return Symbols.diamond;
|
|
||||||
default:
|
|
||||||
return Symbols.workspace_premium;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (!membership.isActive) return const SizedBox.shrink();
|
if (!membership.isActive) return const SizedBox.shrink();
|
||||||
|
|
||||||
final tierName = _getMembershipTierName(membership.identifier);
|
final tierName = _getMembershipTierName(membership.identifier);
|
||||||
final tierColor = _getMembershipTierColor(membership.identifier);
|
final tierColor = _getMembershipTierColor(membership.identifier);
|
||||||
final tierIcon = _getMembershipTierIcon(membership.identifier);
|
final tierIcon = Symbols.award_star;
|
||||||
|
|
||||||
return Tooltip(
|
return Tooltip(
|
||||||
richMessage: TextSpan(
|
richMessage: TextSpan(
|
||||||
@ -124,7 +123,7 @@ class StellarMembershipMark extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
TextSpan(text: '\n'),
|
TextSpan(text: '\n'),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: 'currentMembership'.tr(args: [tierName]),
|
text: 'currentMembershipMember'.tr(args: [tierName]),
|
||||||
style: TextStyle(fontWeight: FontWeight.normal),
|
style: TextStyle(fontWeight: FontWeight.normal),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -244,7 +244,7 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
String _formatFileSize(int bytes) {
|
String formatFileSize(int bytes) {
|
||||||
if (bytes <= 0) return '0 B';
|
if (bytes <= 0) return '0 B';
|
||||||
if (bytes < 1024) return '$bytes B';
|
if (bytes < 1024) return '$bytes B';
|
||||||
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(2)} KB';
|
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(2)} KB';
|
||||||
@ -274,7 +274,7 @@ class CloudFileZoomIn extends HookConsumerWidget {
|
|||||||
buildInfoRow(
|
buildInfoRow(
|
||||||
Icons.storage,
|
Icons.storage,
|
||||||
'Size',
|
'Size',
|
||||||
_formatFileSize(item.size),
|
formatFileSize(item.size),
|
||||||
),
|
),
|
||||||
const Divider(height: 1),
|
const Divider(height: 1),
|
||||||
buildInfoRow(
|
buildInfoRow(
|
||||||
|
@ -286,7 +286,7 @@ class _PaymentContentState extends ConsumerState<_PaymentContent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _formatCurrency(int amount, String currency) {
|
String _formatCurrency(int amount, String currency) {
|
||||||
final value = amount / 100.0;
|
final value = amount;
|
||||||
return '${value.toStringAsFixed(2)} $currency';
|
return '${value.toStringAsFixed(2)} $currency';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user