diff --git a/lib/constants/app_info.dart b/lib/constants/app_info.dart index f3485f04..a34381dc 100644 --- a/lib/constants/app_info.dart +++ b/lib/constants/app_info.dart @@ -1,8 +1,8 @@ import 'package:flutter/foundation.dart'; class AppInfo { - static const String version = '5.0.8'; - static const String buildNumber = '157'; + static const String version = '5.1.0'; + static const String buildNumber = '158'; static const String gitCommit = String.fromEnvironment('GIT_COMMIT'); static String get shortGitCommit => diff --git a/lib/screens/settings/donate_page.dart b/lib/screens/settings/donate_page.dart index b47efc72..e9aca0bb 100644 --- a/lib/screens/settings/donate_page.dart +++ b/lib/screens/settings/donate_page.dart @@ -79,11 +79,6 @@ class _DonatePageState extends State { const SizedBox(height: 16), ], _DonateLinksCard(colorScheme: colorScheme, config: _config), - const SizedBox(height: 24), - _RecentDonorsCard( - colorScheme: colorScheme, - supporters: _config.supporters, - ), const SizedBox(height: 16), _DonateNoticeCard( colorScheme: colorScheme, @@ -212,15 +207,6 @@ class _MonthlyDonationGoalCard extends StatelessWidget { style: theme.textTheme.bodyMedium, ), ], - if (goal.showSupporterCount) ...[ - const SizedBox(height: 12), - Text( - '${NumberFormat.decimalPattern(locale).format(goal.supporterCount)} supporters', - style: theme.textTheme.bodyMedium?.copyWith( - color: colorScheme.onSurfaceVariant, - ), - ), - ], if (goal.showSourceBreakdown && goal.sources.isNotEmpty) ...[ const SizedBox(height: 16), for (final entry in goal.sources.entries) @@ -236,8 +222,6 @@ class _MonthlyDonationGoalCard extends StatelessWidget { }, if (goal.showAmounts && entry.value.amount != null) currencyFormat.format(entry.value.amount), - if (goal.showSupporterCount) - '${NumberFormat.decimalPattern(locale).format(entry.value.supporterCount)} supporters', ].join(' ยท '), style: theme.textTheme.bodySmall?.copyWith( color: colorScheme.onSurfaceVariant, @@ -281,33 +265,12 @@ class _DonateLinksCard extends StatelessWidget { children: [ Padding( padding: const EdgeInsets.fromLTRB(20, 18, 20, 14), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - config.title, - style: Theme.of(context).textTheme.titleMedium - ?.copyWith( - fontWeight: FontWeight.w700, - color: colorScheme.onSurface, - ), - ), - const SizedBox(height: 4), - Text( - config.message, - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: colorScheme.onSurfaceVariant, - height: 1.35, - ), - ), - ], - ), - ), - ], + child: Text( + config.title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w700, + color: colorScheme.onSurface, + ), ), ), Divider( @@ -346,102 +309,6 @@ class _DonateLinksCard extends StatelessWidget { } } -class _RecentDonorsCard extends StatelessWidget { - final ColorScheme colorScheme; - final List supporters; - - const _RecentDonorsCard({ - required this.colorScheme, - required this.supporters, - }); - - @override - Widget build(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - final cardColor = isDark - ? Color.alphaBlend( - Colors.white.withValues(alpha: 0.08), - colorScheme.surface, - ) - : Color.alphaBlend( - Colors.black.withValues(alpha: 0.04), - colorScheme.surface, - ); - - return Card( - elevation: 0, - color: cardColor, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), - child: Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.star_rounded, size: 20, color: colorScheme.primary), - const SizedBox(width: 8), - Text( - 'Recent Supporters', - style: Theme.of(context).textTheme.titleMedium?.copyWith( - fontWeight: FontWeight.w600, - color: colorScheme.onSurface, - ), - ), - ], - ), - const SizedBox(height: 4), - Text( - 'Thank you for your generosity!', - style: Theme.of(context).textTheme.bodySmall?.copyWith( - color: colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(height: 16), - if (supporters.isEmpty) - Center( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Column( - children: [ - Icon( - Icons.emoji_events_outlined, - size: 32, - color: colorScheme.onSurfaceVariant.withValues( - alpha: 0.4, - ), - ), - const SizedBox(height: 8), - Text( - 'No supporters yet - be the first!', - style: Theme.of(context).textTheme.bodyMedium?.copyWith( - color: colorScheme.onSurfaceVariant.withValues( - alpha: 0.6, - ), - ), - ), - ], - ), - ), - ) - else - Wrap( - spacing: 8, - runSpacing: 8, - children: supporters - .map( - (name) => - _SupporterChip(name: name, colorScheme: colorScheme), - ) - .toList(), - ), - ], - ), - ), - ); - } -} - class _DonateNoticeCard extends StatelessWidget { final ColorScheme colorScheme; final List notices; @@ -579,49 +446,6 @@ class _DonateMethodItem extends StatelessWidget { } } -class _SupporterChip extends StatelessWidget { - final String name; - final ColorScheme colorScheme; - - const _SupporterChip({required this.name, required this.colorScheme}); - - @override - Widget build(BuildContext context) { - return Material( - color: colorScheme.secondaryContainer, - borderRadius: BorderRadius.circular(20), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - CircleAvatar( - radius: 10, - backgroundColor: colorScheme.primary.withValues(alpha: 0.2), - child: Text( - name.isNotEmpty ? name[0].toUpperCase() : '?', - style: TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: colorScheme.primary, - ), - ), - ), - const SizedBox(width: 8), - Text( - name, - style: Theme.of(context).textTheme.labelLarge?.copyWith( - color: colorScheme.onSecondaryContainer, - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - ); - } -} - class _NoticeLine extends StatelessWidget { final IconData icon; final String text; diff --git a/lib/services/app_remote_config_service.dart b/lib/services/app_remote_config_service.dart index 0ab02f3a..d7fe4a99 100644 --- a/lib/services/app_remote_config_service.dart +++ b/lib/services/app_remote_config_service.dart @@ -162,8 +162,8 @@ class DonateConfig { return DonateConfig( enabled: json['enabled'] as bool? ?? true, title: _readString(json['title']).isEmpty - ? 'Support Development' - : _readString(json['title']), + ? 'Support SpotiFLAC-Mobile' + : _mobileDonationText(_readString(json['title'])), message: _readString(json['message']).isEmpty ? 'Optional support helps cover tools, testing devices, and hosting.' : _readString(json['message']), @@ -185,7 +185,7 @@ class DonateConfig { factory DonateConfig.fallback() { return const DonateConfig( enabled: true, - title: 'Support Development', + title: 'Support SpotiFLAC-Mobile', message: 'Optional support helps cover dev tools and testing devices.', methods: [ DonateMethod( @@ -272,8 +272,11 @@ class MonthlyDonationGoal { enabled: _readBool(json['enabled']), active: _readBool(json['active']), period: _readString(json['period']), - title: _readNullableString(json['title']) ?? 'Monthly development goal', - description: _readString(json['description']), + title: _mobileDonationText( + _readNullableString(json['title']) ?? + 'Monthly SpotiFLAC-Mobile development goal', + ), + description: _mobileDonationText(_readString(json['description'])), progressPercent: (_readFiniteNumber(json['progress_percent']) ?? 0).clamp( 0, double.maxFinite, @@ -500,6 +503,11 @@ String _readString(Object? value) { return value is String ? value.trim() : ''; } +String _mobileDonationText(String text) => text.replaceAll( + RegExp(r'\bSpotiFLAC(?:[ -]+Mobile)?\b', caseSensitive: false), + 'SpotiFLAC-Mobile', +); + double? _readFiniteNumber(Object? value) { final number = value is num ? value.toDouble() diff --git a/pubspec.yaml b/pubspec.yaml index 01863359..edd03d4b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: spotiflac_android description: Extension-driven music metadata and downloads for mobile devices publish_to: "none" -version: 5.0.8+157 +version: 5.1.0+158 environment: sdk: ^3.10.0 diff --git a/test/app_remote_config_service_test.dart b/test/app_remote_config_service_test.dart index 0abbea4d..d7da0e81 100644 --- a/test/app_remote_config_service_test.dart +++ b/test/app_remote_config_service_test.dart @@ -63,7 +63,7 @@ void main() { }); for (final brightness in Brightness.values) { - testWidgets('monthly goal respects hidden amounts in $brightness', ( + testWidgets('monthly goal shows progress without counts in $brightness', ( tester, ) async { tester.view.physicalSize = const Size(430, 932); @@ -97,7 +97,7 @@ void main() { expect(find.text('Monthly development goal'), findsOneWidget); expect(find.text('Oktober 2026'), findsOneWidget); expect(find.text('9%'), findsOneWidget); - expect(find.text('14 supporters'), findsOneWidget); + expect(find.text('14 supporters'), findsNothing); expect( tester .widget( @@ -150,7 +150,7 @@ void main() { 'display': { 'amounts': true, 'percentage': false, - 'supporter_count': false, + 'supporter_count': true, 'source_breakdown': true, }, },