Compare commits

..

No commits in common. "13ea182707d7d7ea7f84ccfaea2a4929d9f5cdbe" and "d414695eb32812248267328c0d846b8a927fe62d" have entirely different histories.

9 changed files with 672 additions and 668 deletions

View File

@ -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,19 +538,29 @@
"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": "1200 NSP per month, level 3+ required", "membershipPriceStellar": "10 NS$ per month",
"membershipPriceNova": "2400 NSP per month, level 6+ required", "membershipPriceNova": "20 NS$ per month",
"membershipPriceSupernova": "3600 NSP per month, level 9+ required", "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",
"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.",
@ -587,7 +597,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.",
@ -668,27 +678,5 @@
"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"
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,7 @@
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});
@ -14,8 +12,8 @@ class AboutScreen extends StatefulWidget {
class _AboutScreenState extends State<AboutScreen> { class _AboutScreenState extends State<AboutScreen> {
PackageInfo _packageInfo = PackageInfo( PackageInfo _packageInfo = PackageInfo(
appName: 'Solian', appName: 'Island',
packageName: 'dev.solsynth.solian', packageName: 'com.example.island',
version: '1.0.0', version: '1.0.0',
buildNumber: '1', buildNumber: '1',
); );
@ -40,9 +38,7 @@ class _AboutScreenState extends State<AboutScreen> {
} catch (e) { } catch (e) {
if (mounted) { if (mounted) {
setState(() { setState(() {
_errorMessage = 'aboutScreenFailedToLoadPackageInfo'.tr( _errorMessage = 'Failed to load package info: $e';
args: [e.toString()],
);
_isLoading = false; _isLoading = false;
}); });
} }
@ -61,7 +57,7 @@ class _AboutScreenState extends State<AboutScreen> {
final theme = Theme.of(context); final theme = Theme.of(context);
return Scaffold( return Scaffold(
appBar: AppBar(title: Text('about'.tr()), elevation: 0), appBar: AppBar(title: const Text('About'), elevation: 0),
body: body:
_isLoading _isLoading
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
@ -92,9 +88,7 @@ class _AboutScreenState extends State<AboutScreen> {
), ),
), ),
Text( Text(
'aboutScreenVersionInfo'.tr( 'Version ${_packageInfo.version} (${_packageInfo.buildNumber})',
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,
), ),
@ -104,24 +98,24 @@ class _AboutScreenState extends State<AboutScreen> {
// App Info Card // App Info Card
_buildSection( _buildSection(
context, context,
title: 'aboutScreenAppInfoSectionTitle'.tr(), title: 'App Information',
children: [ children: [
_buildInfoItem( _buildInfoItem(
context, context,
icon: Icons.info_outline, icon: Icons.info_outline,
label: 'aboutScreenPackageNameLabel'.tr(), label: 'Package Name',
value: _packageInfo.packageName, value: _packageInfo.packageName,
), ),
_buildInfoItem( _buildInfoItem(
context, context,
icon: Icons.update, icon: Icons.update,
label: 'aboutScreenVersionLabel'.tr(), label: 'Version',
value: _packageInfo.version, value: _packageInfo.version,
), ),
_buildInfoItem( _buildInfoItem(
context, context,
icon: Icons.build, icon: Icons.build,
label: 'aboutScreenBuildNumberLabel'.tr(), label: 'Build Number',
value: _packageInfo.buildNumber, value: _packageInfo.buildNumber,
), ),
], ],
@ -132,12 +126,12 @@ class _AboutScreenState extends State<AboutScreen> {
// Links Card // Links Card
_buildSection( _buildSection(
context, context,
title: 'aboutScreenLinksSectionTitle'.tr(), title: 'Links',
children: [ children: [
_buildListTile( _buildListTile(
context, context,
icon: Icons.privacy_tip_outlined, icon: Icons.privacy_tip_outlined,
title: 'aboutScreenPrivacyPolicyTitle'.tr(), title: 'Privacy Policy',
onTap: onTap:
() => _launchURL( () => _launchURL(
'https://solsynth.dev/terms/privacy-policy', 'https://solsynth.dev/terms/privacy-policy',
@ -146,16 +140,16 @@ class _AboutScreenState extends State<AboutScreen> {
_buildListTile( _buildListTile(
context, context,
icon: Icons.description_outlined, icon: Icons.description_outlined,
title: 'aboutScreenTermsOfServiceTitle'.tr(), title: 'Terms of Service',
onTap: onTap:
() => _launchURL( () => _launchURL(
'https://solsynth.dev/terms/basic-law', 'https://example.com/terms/basic-law',
), ),
), ),
_buildListTile( _buildListTile(
context, context,
icon: Icons.code, icon: Icons.code,
title: 'aboutScreenOpenSourceLicensesTitle'.tr(), title: 'Open Source Licenses',
onTap: () { onTap: () {
showLicensePage( showLicensePage(
context: context, context: context,
@ -173,22 +167,21 @@ class _AboutScreenState extends State<AboutScreen> {
// Developer Info // Developer Info
_buildSection( _buildSection(
context, context,
title: 'aboutScreenDeveloperSectionTitle'.tr(), title: 'Developer',
children: [ children: [
_buildListTile( _buildListTile(
context, context,
icon: Icons.email_outlined, icon: Icons.email_outlined,
title: 'aboutScreenContactUsTitle'.tr(), title: 'Contact Us',
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: 'aboutScreenLicenseTitle'.tr(), title: 'License',
subtitle: 'aboutScreenLicenseContent'.tr( subtitle:
args: [DateTime.now().year.toString()], 'Copyright reserved © ${DateTime.now().year} Solsynth\nGNU Affero General Public License v3.0',
),
onTap: onTap:
() => _launchURL( () => _launchURL(
'https://github.com/Solsynth/Solian/blob/v3/LICENSE.txt', 'https://github.com/Solsynth/Solian/blob/v3/LICENSE.txt',
@ -203,9 +196,7 @@ class _AboutScreenState extends State<AboutScreen> {
Padding( Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Text( child: Text(
'aboutScreenCopyright'.tr( '© ${DateTime.now().year} ${_packageInfo.appName}. All rights reserved.',
args: [DateTime.now().year.toString(), "Solsynth"],
),
style: theme.textTheme.bodySmall, style: theme.textTheme.bodySmall,
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
@ -273,12 +264,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(
SnackBar(content: Text('copiedToClipboard'.tr())), const SnackBar(content: Text('Copied to clipboard')),
); );
}, },
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
constraints: const BoxConstraints(), constraints: const BoxConstraints(),
tooltip: 'copyToClipboardTooltip'.tr(), tooltip: 'Copy to clipboard',
), ),
], ],
), ),
@ -292,18 +283,13 @@ 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).padding(top: multipleLines ? 8 : 0), leading: Icon(icon),
title: Text(title), title: Text(title),
subtitle: subtitle != null ? Text(subtitle) : null, subtitle: subtitle != null ? Text(subtitle) : null,
isThreeLine: multipleLines, trailing: const Icon(Icons.chevron_right),
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,

View File

@ -1,7 +1,4 @@
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';
@ -17,9 +14,7 @@ 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';
@ -89,6 +84,35 @@ 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,
),
),
],
),
),
], ],
), ),
), ),
@ -268,31 +292,6 @@ 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),
@ -308,7 +307,7 @@ class LevelingScreen extends HookConsumerWidget {
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
children: [ children: [
@ -328,42 +327,27 @@ class LevelingScreen extends HookConsumerWidget {
if (isActive) ...[ if (isActive) ...[
_buildCurrentMembershipCard(context, membership!), _buildCurrentMembershipCard(context, membership!),
const Gap(12), const Gap(16),
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 OutlinedButton.icon(
if (kIsWeb || !(Platform.isIOS || Platform.isMacOS)) onPressed: () => _showRestorePurchaseSheet(context, ref),
OutlinedButton.icon( icon: const Icon(Icons.restore),
onPressed: () => _showRestorePurchaseSheet(context, ref), label: Text('restorePurchase'.tr()),
icon: const Icon(Icons.restore), style: OutlinedButton.styleFrom(
label: Text('restorePurchase'.tr()), minimumSize: const Size(double.infinity, 48),
style: OutlinedButton.styleFrom( ),
minimumSize: const Size(double.infinity, 48), ),
),
).padding(top: 12),
], ],
), ),
); );
@ -426,18 +410,33 @@ 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(),
'color': Colors.indigo, 'features': [
'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,
}, },
]; ];

View File

@ -9,6 +9,7 @@ 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';

View File

@ -341,6 +341,26 @@ 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(),

View File

@ -21,23 +21,11 @@ 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: nameStyle)), Flexible(child: Text(account.nick, style: style)),
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)
@ -99,23 +87,36 @@ 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.blue;
case 'solian.stellar.nova':
return Colors.indigo;
case 'solian.stellar.supernova':
return Colors.amber; return Colors.amber;
case 'solian.stellar.nova':
return Colors.blue;
case 'solian.stellar.supernova':
return Colors.purple;
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 = Symbols.award_star; final tierIcon = _getMembershipTierIcon(membership.identifier);
return Tooltip( return Tooltip(
richMessage: TextSpan( richMessage: TextSpan(
@ -123,7 +124,7 @@ class StellarMembershipMark extends StatelessWidget {
children: [ children: [
TextSpan(text: '\n'), TextSpan(text: '\n'),
TextSpan( TextSpan(
text: 'currentMembershipMember'.tr(args: [tierName]), text: 'currentMembership'.tr(args: [tierName]),
style: TextStyle(fontWeight: FontWeight.normal), style: TextStyle(fontWeight: FontWeight.normal),
), ),
], ],

View File

@ -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(

View File

@ -286,7 +286,7 @@ class _PaymentContentState extends ConsumerState<_PaymentContent> {
} }
String _formatCurrency(int amount, String currency) { String _formatCurrency(int amount, String currency) {
final value = amount; final value = amount / 100.0;
return '${value.toStringAsFixed(2)} $currency'; return '${value.toStringAsFixed(2)} $currency';
} }