From cd62a0a4288c7d914f93f97371b84c4c8294d18d Mon Sep 17 00:00:00 2001 From: Ruslan Bakiev <572431+veikab@users.noreply.github.com> Date: Fri, 8 May 2026 19:14:08 +0700 Subject: [PATCH] Polish Telegram auth UI state --- lib/auth/telegram_login_button_web.dart | 1 + lib/screens/mapflow_shell.dart | 78 +++++++++++++++++++++---- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/lib/auth/telegram_login_button_web.dart b/lib/auth/telegram_login_button_web.dart index d5ee161..dd47d78 100644 --- a/lib/auth/telegram_login_button_web.dart +++ b/lib/auth/telegram_login_button_web.dart @@ -37,6 +37,7 @@ class _TelegramLoginButtonState extends State { if (mounted) { widget.onAuthenticated(); } + web.window.location.reload(); }).toJS; _window.setProperty(_callbackName.toJS, callback); ui_web.platformViewRegistry.registerViewFactory(_viewType, _buildElement); diff --git a/lib/screens/mapflow_shell.dart b/lib/screens/mapflow_shell.dart index 0082aeb..e1f815e 100644 --- a/lib/screens/mapflow_shell.dart +++ b/lib/screens/mapflow_shell.dart @@ -44,6 +44,9 @@ class _MapContent extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final selected = state.selectedPlace; + final availableTraits = { + for (final place in state.recommendations) ...place.traits, + }.toList(); return Scaffold( body: Stack( @@ -78,10 +81,20 @@ class _MapContent extends ConsumerWidget { ), SafeArea( child: Align( - alignment: Alignment.topCenter, - child: _TraitBar(selectedTrait: state.selectedTrait), + alignment: Alignment.topLeft, + child: _UserAvatar(user: state.currentUser), ), ), + if (availableTraits.isNotEmpty) + SafeArea( + child: Align( + alignment: Alignment.topCenter, + child: _TraitBar( + selectedTrait: state.selectedTrait, + traits: availableTraits, + ), + ), + ), Align( alignment: Alignment.bottomCenter, child: SafeArea( @@ -124,6 +137,48 @@ class _MapContent extends ConsumerWidget { } } +class _UserAvatar extends StatelessWidget { + const _UserAvatar({required this.user}); + + final AppUser? user; + + @override + Widget build(BuildContext context) { + final photoUrl = user?.photoUrl; + final fallback = _fallbackText(); + + return Padding( + padding: const EdgeInsets.only(left: 12, top: 8), + child: CircleAvatar( + radius: 22, + backgroundColor: const Color(0xFFFFFBF5), + foregroundColor: const Color(0xFF17211D), + backgroundImage: photoUrl == null ? null : NetworkImage(photoUrl), + child: photoUrl == null + ? Text( + fallback, + style: const TextStyle(fontWeight: FontWeight.w900), + ) + : null, + ), + ); + } + + String _fallbackText() { + final firstName = user?.firstName?.trim(); + if (firstName != null && firstName.isNotEmpty) { + return firstName.characters.first.toUpperCase(); + } + + final username = user?.username?.trim(); + if (username != null && username.isNotEmpty) { + return username.characters.first.toUpperCase(); + } + + return 'M'; + } +} + class _TelegramLoginScreen extends StatelessWidget { const _TelegramLoginScreen({required this.onAuthenticated}); @@ -264,23 +319,24 @@ class _MapAttribution extends StatelessWidget { } class _TraitBar extends ConsumerWidget { - const _TraitBar({required this.selectedTrait}); + const _TraitBar({required this.selectedTrait, required this.traits}); final PlaceTrait selectedTrait; + final List traits; @override Widget build(BuildContext context, WidgetRef ref) { final controller = ref.read(placeControllerProvider.notifier); - return Container( - height: 58, - margin: const EdgeInsets.fromLTRB(10, 8, 10, 0), + return SizedBox( + height: 54, child: ListView.separated( scrollDirection: Axis.horizontal, - itemCount: PlaceTrait.values.length, - separatorBuilder: (_, _) => const SizedBox(width: 8), + padding: const EdgeInsets.fromLTRB(68, 8, 12, 0), + itemCount: traits.length, + separatorBuilder: (_, _) => const SizedBox(width: 6), itemBuilder: (context, index) { - final item = PlaceTrait.values[index]; + final item = traits[index]; return ChoiceChip( avatar: Icon(item.icon, size: 17), label: Text(item.label), @@ -288,7 +344,9 @@ class _TraitBar extends ConsumerWidget { onSelected: (_) => controller.selectTrait(item), backgroundColor: const Color(0xFFFFFBF5), selectedColor: Theme.of(context).colorScheme.primaryContainer, - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10), + side: BorderSide.none, + shape: const StadiumBorder(), + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 9), ); }, ),