diff --git a/lib/core/features/events/presentation/event_detail/event_detail_screen.dart b/lib/core/features/events/presentation/event_detail/event_detail_screen.dart index c9852c4..233a13f 100644 --- a/lib/core/features/events/presentation/event_detail/event_detail_screen.dart +++ b/lib/core/features/events/presentation/event_detail/event_detail_screen.dart @@ -155,17 +155,18 @@ class _EventDetailScreenState extends ConsumerState { child: Center(child: SignUpButton(event: event)), ), if (userAsync.hasValue && !isEditing) - isPast - ? AttendanceList( - eventId: widget.id, - isAdmin: userAsync.value?.role.canEditEvent == true, - onAddAttendee: () => - context.push(AddAttendeeScreen.getPath(widget.id)), - ) - : (userAsync.value?.role.canEditEvent == true - ? SliverToBoxAdapter(child: SignUpList(eventId: widget.id)) - : const SliverToBoxAdapter(child: SizedBox.shrink())), - if (userAsync.hasValue && userAsync.value == null) + if (userAsync.value?.role.canEditEvent == true) + isPast + ? AttendanceList( + eventId: widget.id, + isAdmin: true, + onAddAttendee: () => + context.push(AddAttendeeScreen.getPath(widget.id)), + ) + : SliverToBoxAdapter(child: SignUpList(eventId: widget.id)) + else + const SliverToBoxAdapter(child: SizedBox.shrink()), + if (!isPast && userAsync.hasValue && userAsync.value == null) SliverToBoxAdapter( child: Padding( padding: .only( diff --git a/lib/core/features/events/presentation/event_feed/event_feed_screen.dart b/lib/core/features/events/presentation/event_feed/event_feed_screen.dart index 2b8115e..4f13d3e 100644 --- a/lib/core/features/events/presentation/event_feed/event_feed_screen.dart +++ b/lib/core/features/events/presentation/event_feed/event_feed_screen.dart @@ -52,14 +52,14 @@ class _EventFeedScreenState extends ConsumerState { _welcomeChecked = true; final prefs = await ref.read(appPreferencesProvider.future); - if (prefs.getWelcomeMessageSeen()) return; final remoteConfig = await ref.read(remoteConfigProvider.future); final message = remoteConfig.welcomeMessage; if (message.isEmpty) return; + if (prefs.getWelcomeMessageContent() == message) return; if (!mounted) return; - await prefs.setWelcomeMessageSeen(); + await prefs.setWelcomeMessageContent(message); if (!mounted) return; context.showModal( _WelcomeMessageModal( @@ -177,6 +177,15 @@ class _EventFeedScreenState extends ConsumerState { } } + if (!isAuthenticated) { + slivers.add( + SliverToBoxAdapter( + child: DashboardSectionHeader(title: loc.dashboardCalendar), + ), + ); + slivers.add(const SliverToBoxAdapter(child: DashboardCalendarCard())); + } + slivers.add( SliverToBoxAdapter( child: DashboardSectionHeader(title: loc.dashboardUpcomingEvents), diff --git a/lib/core/features/onboarding/presentation/onboarding/welcome_screen.dart b/lib/core/features/onboarding/presentation/onboarding/welcome_screen.dart index 9b145f9..aa52bf3 100644 --- a/lib/core/features/onboarding/presentation/onboarding/welcome_screen.dart +++ b/lib/core/features/onboarding/presentation/onboarding/welcome_screen.dart @@ -8,7 +8,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:anystep/core/features/onboarding/presentation/onboarding/welcome_screen_controller.dart'; import 'package:go_router/go_router.dart'; import 'package:anystep/l10n/generated/app_localizations.dart'; -import 'package:anystep/core/features/settings/presentation/locale_setting.dart'; +import 'package:anystep/core/features/settings/presentation/widgets/locale_setting.dart'; /// Multi-page onboarding / welcome flow. /// Shows 4 pages in a PageView with a dot indicator. The final page displays diff --git a/lib/core/features/profile/presentation/agreement/locale_icon_button.dart b/lib/core/features/profile/presentation/agreement/locale_icon_button.dart index 04a7666..bf5a1f0 100644 --- a/lib/core/features/profile/presentation/agreement/locale_icon_button.dart +++ b/lib/core/features/profile/presentation/agreement/locale_icon_button.dart @@ -1,5 +1,5 @@ import 'package:anystep/core/config/locale/locale_controller.dart'; -import 'package:anystep/core/features/settings/presentation/locale_setting.dart'; +import 'package:anystep/core/features/settings/presentation/widgets/locale_setting.dart'; import 'package:anystep/l10n/generated/app_localizations.dart'; import 'package:anystep/core/common/widgets/any_step_modal.dart'; import 'package:flutter/material.dart'; diff --git a/lib/core/features/settings/presentation/settings_screen.dart b/lib/core/features/settings/presentation/settings_screen.dart index fa81535..82a5f94 100644 --- a/lib/core/features/settings/presentation/settings_screen.dart +++ b/lib/core/features/settings/presentation/settings_screen.dart @@ -2,8 +2,9 @@ import 'package:anystep/core/common/constants/spacing.dart'; import 'package:anystep/core/common/widgets/widgets.dart'; import 'package:anystep/core/features/auth/data/auth_repository.dart'; import 'package:anystep/core/features/screens.dart'; -import 'package:anystep/core/features/settings/presentation/theme_mode_setting.dart'; -import 'package:anystep/core/features/settings/presentation/locale_setting.dart'; +import 'package:anystep/core/features/settings/presentation/widgets/donate_tile.dart'; +import 'package:anystep/core/features/settings/presentation/widgets/theme_mode_setting.dart'; +import 'package:anystep/core/features/settings/presentation/widgets/locale_setting.dart'; import 'package:anystep/l10n/generated/app_localizations.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -37,6 +38,7 @@ class SettingsScreen extends ConsumerWidget { trailing: const Icon(Icons.chevron_right), onTap: () => context.push(AboutScreen.path), ), + const DonateTile(), const ThemeModeSetting(), const LocaleSetting(), ListTile( diff --git a/lib/core/features/settings/presentation/widgets/donate_tile.dart b/lib/core/features/settings/presentation/widgets/donate_tile.dart new file mode 100644 index 0000000..3978e51 --- /dev/null +++ b/lib/core/features/settings/presentation/widgets/donate_tile.dart @@ -0,0 +1,35 @@ +import 'package:anystep/core/common/utils/log_utils.dart'; +import 'package:anystep/l10n/generated/app_localizations.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class DonateTile extends StatelessWidget { + const DonateTile({super.key}); + + static const _donateUrl = + 'https://www.zeffy.com/en-US/donation-form/high-five-for-seniors-step-up-give-back-move-forward'; + + Future _openLink(String url) async { + final uri = Uri.tryParse(url); + if (uri == null) return; + try { + final launched = await launchUrl(uri, mode: LaunchMode.externalApplication); + if (!launched) { + Log.e('Failed to open external link: $uri'); + } + } catch (e) { + Log.e('Error opening external link', e); + } + } + + @override + Widget build(BuildContext context) { + final loc = AppLocalizations.of(context); + return ListTile( + leading: const Icon(Icons.volunteer_activism), + title: Text(loc.donate), + trailing: const Icon(Icons.open_in_new), + onTap: () => _openLink(_donateUrl), + ); + } +} diff --git a/lib/core/features/settings/presentation/locale_setting.dart b/lib/core/features/settings/presentation/widgets/locale_setting.dart similarity index 98% rename from lib/core/features/settings/presentation/locale_setting.dart rename to lib/core/features/settings/presentation/widgets/locale_setting.dart index 0ec8b1c..0a7c6a6 100644 --- a/lib/core/features/settings/presentation/locale_setting.dart +++ b/lib/core/features/settings/presentation/widgets/locale_setting.dart @@ -18,7 +18,6 @@ class LocaleSetting extends ConsumerWidget { return ListTile( leading: const Icon(Icons.language), title: Text(loc.languageLabel), - subtitle: Text(_labelForLocale(current, loc)), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ diff --git a/lib/core/features/settings/presentation/theme_mode_setting.dart b/lib/core/features/settings/presentation/widgets/theme_mode_setting.dart similarity index 100% rename from lib/core/features/settings/presentation/theme_mode_setting.dart rename to lib/core/features/settings/presentation/widgets/theme_mode_setting.dart diff --git a/lib/core/shared_prefs/shared_prefs.dart b/lib/core/shared_prefs/shared_prefs.dart index 1c0df7b..2002d75 100644 --- a/lib/core/shared_prefs/shared_prefs.dart +++ b/lib/core/shared_prefs/shared_prefs.dart @@ -14,7 +14,7 @@ class AppPreferences { static const String themeModeKey = 'theme_mode'; static const String localeCodeKey = 'locale_code'; static const String eventNotificationsKey = 'event_notifications'; - static const String welcomeMessageSeenKey = 'welcome_message_seen'; + static const String welcomeMessageContentKey = 'welcome_message_content'; String? getAuthStateJson() => _prefs.getString(authStateKey); Future setAuthStateJson(String token) async => await _prefs.setString(authStateKey, token); @@ -44,10 +44,11 @@ class AppPreferences { Future clearEventNotificationsEnabled() async => await _prefs.remove(eventNotificationsKey); - bool getWelcomeMessageSeen() => _prefs.getBool(welcomeMessageSeenKey) ?? false; - Future setWelcomeMessageSeen({bool seen = true}) async => - await _prefs.setBool(welcomeMessageSeenKey, seen); - Future clearWelcomeMessageSeen() async => await _prefs.remove(welcomeMessageSeenKey); + String? getWelcomeMessageContent() => _prefs.getString(welcomeMessageContentKey); + Future setWelcomeMessageContent(String message) async => + await _prefs.setString(welcomeMessageContentKey, message); + Future clearWelcomeMessageContent() async => + await _prefs.remove(welcomeMessageContentKey); } @Riverpod(keepAlive: true) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f057282..31cb256 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -25,6 +25,8 @@ , "settingsTitle": "Settings", "@settingsTitle": {"description": "Title for the Settings screen app bar"}, + "donate": "Donate", + "@donate": {"description": "Label for the donate link in settings"}, "themeLabel": "Theme", "@themeLabel": {"description": "Settings tile label for theme selection"}, "themeAuto": "Auto", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index e49632a..81212e8 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -25,6 +25,8 @@ , "settingsTitle": "Configuración", "@settingsTitle": {"description": "Título de la pantalla de configuración"}, + "donate": "Donar", + "@donate": {"description": "Etiqueta del enlace de donación en configuración"}, "themeLabel": "Tema", "@themeLabel": {"description": "Etiqueta para selección de tema"}, "themeAuto": "Automático", diff --git a/lib/l10n/generated/app_localizations.dart b/lib/l10n/generated/app_localizations.dart index ab81616..22fce69 100644 --- a/lib/l10n/generated/app_localizations.dart +++ b/lib/l10n/generated/app_localizations.dart @@ -134,6 +134,12 @@ abstract class AppLocalizations { /// **'Settings'** String get settingsTitle; + /// Label for the donate link in settings + /// + /// In en, this message translates to: + /// **'Donate'** + String get donate; + /// Settings tile label for theme selection /// /// In en, this message translates to: diff --git a/lib/l10n/generated/app_localizations_en.dart b/lib/l10n/generated/app_localizations_en.dart index 34b1ac3..911000f 100644 --- a/lib/l10n/generated/app_localizations_en.dart +++ b/lib/l10n/generated/app_localizations_en.dart @@ -37,6 +37,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settingsTitle => 'Settings'; + @override + String get donate => 'Donate'; + @override String get themeLabel => 'Theme'; diff --git a/lib/l10n/generated/app_localizations_es.dart b/lib/l10n/generated/app_localizations_es.dart index b6f7c27..10f60e5 100644 --- a/lib/l10n/generated/app_localizations_es.dart +++ b/lib/l10n/generated/app_localizations_es.dart @@ -37,6 +37,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get settingsTitle => 'Configuración'; + @override + String get donate => 'Donar'; + @override String get themeLabel => 'Tema';