From 42812f9e80e3f4dbe9a846267f1564f5f4c20710 Mon Sep 17 00:00:00 2001 From: Thiago Carvalho <32248947+thiagocarvalhodev@users.noreply.github.com> Date: Fri, 13 Dec 2024 12:47:27 -0300 Subject: [PATCH] feat(logo) - add logo on welcome back page --- .../components/login_modal.dart | 63 ++- .../modals/enter_your_password_modal.dart | 413 +++++++++++------- .../fs_entry_preview_cubit.dart | 15 + .../fs_entry_preview_state.dart | 7 + lib/components/profile_card.dart | 156 +++++-- .../presentation/bloc/profile_name_bloc.dart | 21 +- .../presentation/bloc/profile_name_event.dart | 10 + .../presentation/bloc/profile_name_state.dart | 4 +- 8 files changed, 470 insertions(+), 219 deletions(-) diff --git a/lib/authentication/components/login_modal.dart b/lib/authentication/components/login_modal.dart index 84a4c6dc66..712759dd0d 100644 --- a/lib/authentication/components/login_modal.dart +++ b/lib/authentication/components/login_modal.dart @@ -1,4 +1,5 @@ import 'package:ardrive/authentication/components/breakpoint_layout_builder.dart'; +import 'package:ardrive/gar/presentation/widgets/gar_modal.dart'; import 'package:ardrive_ui/ardrive_ui.dart'; import 'package:flutter/material.dart'; @@ -11,6 +12,7 @@ class ArDriveLoginModal extends StatelessWidget { required this.content, this.width, this.hasCloseButton = true, + this.hasSettingsButton = false, this.onClose, this.padding, }); @@ -18,6 +20,7 @@ class ArDriveLoginModal extends StatelessWidget { final Widget content; final double? width; final bool hasCloseButton; + final bool hasSettingsButton; final Function()? onClose; final EdgeInsets? padding; @@ -34,8 +37,8 @@ class ArDriveLoginModal extends StatelessWidget { } final contentPadding = (deviceWidth < TABLET) - ? EdgeInsets.fromLTRB(22, hasCloseButton ? 0 : 44, 22, 32) - : EdgeInsets.fromLTRB(56, hasCloseButton ? 0 : 44, 56, 64); + ? EdgeInsets.fromLTRB(22, hasCloseButton ? 0 : 24, 22, 32) + : EdgeInsets.fromLTRB(56, hasCloseButton ? 0 : 24, 56, 64); return ConstrainedBox( constraints: BoxConstraints( @@ -57,27 +60,45 @@ class ArDriveLoginModal extends StatelessWidget { child: Container( color: colorTokens.containerRed, )), - Row(children: [ - const Spacer(), - if (hasCloseButton) - Padding( - padding: const EdgeInsets.all(22.0), - child: hasCloseButton - ? ArDriveClickArea( - child: GestureDetector( - onTap: onClose ?? () => Navigator.pop(context), - child: const Align( - alignment: Alignment.centerRight, - child: ArDriveIcon( - icon: ArDriveIconsData.x, - size: 20, + Row( + children: [ + const Spacer(), + if (hasCloseButton) + Padding( + padding: const EdgeInsets.all(22.0), + child: hasCloseButton + ? ArDriveClickArea( + child: GestureDetector( + onTap: onClose ?? () => Navigator.pop(context), + child: const Align( + alignment: Alignment.centerRight, + child: ArDriveIcon( + icon: ArDriveIconsData.x, + size: 20, + ), ), ), - ), - ) - : Container(), - ) - ]), + ) + : Container(), + ), + if (!hasCloseButton && hasSettingsButton) + Padding( + padding: const EdgeInsets.only(top: 22.0, right: 22.0), + child: GestureDetector( + onTap: () { + showGatewaySwitcherModal(context); + }, + child: ArDriveClickArea( + tooltip: 'Advanced Settings', + child: Icon( + Icons.settings, + color: colorTokens.iconLow, + ), + ), + ), + ), + ], + ), Padding( padding: padding ?? contentPadding, child: content, diff --git a/lib/authentication/login/views/modals/enter_your_password_modal.dart b/lib/authentication/login/views/modals/enter_your_password_modal.dart index 88f6ea7f51..70add83136 100644 --- a/lib/authentication/login/views/modals/enter_your_password_modal.dart +++ b/lib/authentication/login/views/modals/enter_your_password_modal.dart @@ -2,19 +2,20 @@ import 'package:ardrive/authentication/ardrive_auth.dart'; import 'package:ardrive/authentication/components/biometric_toggle.dart'; import 'package:ardrive/authentication/components/login_modal.dart'; import 'package:ardrive/authentication/login/blocs/login_bloc.dart'; -import 'package:ardrive/components/truncated_address_new.dart'; -import 'package:ardrive/gar/presentation/widgets/gar_modal.dart'; +import 'package:ardrive/components/profile_card.dart'; import 'package:ardrive/misc/resources.dart'; import 'package:ardrive/services/ethereum/provider/ethereum_provider_wallet.dart'; +import 'package:ardrive/user/name/presentation/bloc/profile_name_bloc.dart'; import 'package:ardrive/utils/app_localizations_wrapper.dart'; +import 'package:ardrive/utils/logger.dart'; import 'package:ardrive/utils/plausible_event_tracker/plausible_event_tracker.dart'; import 'package:ardrive/utils/show_general_dialog.dart'; import 'package:ardrive_ui/ardrive_ui.dart'; -import 'package:ario_sdk/ario_sdk.dart'; import 'package:arweave/arweave.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:responsive_builder/responsive_builder.dart'; class EnterYourPasswordWidget extends StatefulWidget { const EnterYourPasswordWidget({ @@ -72,6 +73,18 @@ class _EnterYourPasswordWidgetState extends State { }); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _getWalletAddress().then((walletAddress) { + logger.d('Loading profile name for anonymous user $walletAddress'); + + context + .read() + .add(LoadProfileNameAnonymous(walletAddress ?? '')); + }); + } + @override Widget build(BuildContext context) { final colorTokens = ArDriveTheme.of(context).themeData.colorTokens; @@ -81,170 +94,228 @@ class _EnterYourPasswordWidgetState extends State { widget.derivedEthWallet != null && !widget.loginBloc.existingUserFlow; return SingleChildScrollView( - child: ArDriveLoginModal( - width: 450, - hasCloseButton: !widget.alreadyLoggedIn, - onClose: !widget.alreadyLoggedIn - ? () { - PlausibleEventTracker.trackClickDismissLoginModalIcon( - _getPlausiblePageView(), + child: ScreenTypeLayout.builder( + mobile: (context) => _buildContent( + width: 450, + context: context, + showDerivedWalletAlreadyCreated: showDerivedWalletAlreadyCreated, + ), + tablet: (context) => _buildContent( + width: 450, + context: context, + showDerivedWalletAlreadyCreated: showDerivedWalletAlreadyCreated, + ), + desktop: (context) => _buildContent( + width: 500, + context: context, + showDerivedWalletAlreadyCreated: showDerivedWalletAlreadyCreated, + ), + ), + ); + } + + Widget _buildContent({ + required double width, + required BuildContext context, + required bool showDerivedWalletAlreadyCreated, + }) { + final colorTokens = ArDriveTheme.of(context).themeData.colorTokens; + final typography = ArDriveTypographyNew.of(context); + + return ArDriveLoginModal( + width: width, + hasSettingsButton: true, + hasCloseButton: false, + onClose: !widget.alreadyLoggedIn + ? () { + PlausibleEventTracker.trackClickDismissLoginModalIcon( + _getPlausiblePageView(), + ); + Navigator.of(context).pop(); + widget.loginBloc.add(const ForgetWallet()); + } + : null, + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Center( + child: ArDriveImage( + image: AssetImage(Resources.images.brand.logo1), + height: 36, + )), + const SizedBox(height: 12), + Align( + alignment: Alignment.topCenter, + child: Text( + 'Welcome back', + style: typography.heading2( + color: colorTokens.textHigh, fontWeight: ArFontWeight.bold), + ), + ), + const SizedBox(height: 32), + BlocBuilder( + builder: (context, state) { + if (state is ProfileNameLoaded) { + return ProfileCardHeader( + walletAddress: state.walletAddress, + onPressed: () {}, + isExpanded: true, + hasLogoutButton: true, + logoutTooltip: 'Forget wallet', + onClickLogout: () { + showArDriveDialog(context, + content: + ForgetWalletDialog(loginBloc: widget.loginBloc)); + }, ); - Navigator.of(context).pop(); - widget.loginBloc.add(const ForgetWallet()); } - : null, - content: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Center( - child: ArDriveImage( - image: AssetImage(Resources.images.brand.logo1), - height: 36, - )), - const SizedBox(height: 12), - Align( - alignment: Alignment.topCenter, - child: Text( - 'Enter Your Password', - style: typography.heading2( - color: colorTokens.textHigh, fontWeight: ArFontWeight.bold), - ), - ), - const SizedBox(height: 12), - showDerivedWalletAlreadyCreated - ? Text( - 'We found a wallet already created for this Ethereum address, please enter your password to continue.', - textAlign: TextAlign.center, - style: typography.paragraphNormal( - color: colorTokens.textLow, - fontWeight: ArFontWeight.semiBold), - ) - : Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text(appLocalizationsOf(context).walletAddress, - style: typography.paragraphNormal( - color: colorTokens.textLow, - fontWeight: ArFontWeight.semiBold)), - const SizedBox(width: 8), - FutureBuilder( - future: _getWalletAddress(), - builder: (context, address) => address.hasData - ? TruncatedAddressNew( - walletAddress: address.data!) - : const Text('')) - ], - ), - const SizedBox(height: 40), - Text('Password', - style: typography.paragraphNormal( - color: colorTokens.textLow, - fontWeight: ArFontWeight.semiBold)), - const SizedBox(height: 8), - ArDriveTextFieldNew( - controller: _passwordController, - hintText: 'Enter your password', - showObfuscationToggle: true, - obscureText: true, - autofocus: true, - autofillHints: const [AutofillHints.password], - isEnabled: !widget.checkingPassword, - validator: (value) { - if (value == null || value.isEmpty) { - setState(() { - _isPasswordValid = false; - }); - return appLocalizationsOf(context).validationRequired; - } + return ProfileCardHeader( + walletAddress: state.walletAddress ?? '', + onPressed: () {}, + isExpanded: true, + hasLogoutButton: true, + logoutTooltip: 'Forget wallet', + onClickLogout: () { + showArDriveDialog(context, + content: ForgetWalletDialog(loginBloc: widget.loginBloc)); + }, + ); + }, + ), + showDerivedWalletAlreadyCreated + ? Text( + 'We found a wallet already created for this Ethereum address, please enter your password to continue.', + textAlign: TextAlign.center, + style: typography.paragraphNormal( + color: colorTokens.textLow, + fontWeight: ArFontWeight.semiBold), + ) + : const SizedBox(), + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // crossAxisAlignment: CrossAxisAlignment.center, + // children: [ + // Text(appLocalizationsOf(context).walletAddress, + // style: typography.paragraphNormal( + // color: colorTokens.textLow, + // fontWeight: ArFontWeight.semiBold)), + // const SizedBox(width: 8), + // FutureBuilder( + // future: _getWalletAddress(), + // builder: (context, address) => address.hasData + // ? TruncatedAddressNew( + // walletAddress: address.data!) + // : const Text('')) + // ], + // ), + const SizedBox(height: 40), + Text('Password', + style: typography.paragraphNormal( + color: colorTokens.textLow, + fontWeight: ArFontWeight.semiBold)), + const SizedBox(height: 8), + ArDriveTextFieldNew( + controller: _passwordController, + hintText: 'Enter your password', + showObfuscationToggle: true, + obscureText: true, + autofocus: true, + autofillHints: const [AutofillHints.password], + isEnabled: !widget.checkingPassword, + validator: (value) { + if (value == null || value.isEmpty) { setState(() { - _isPasswordValid = true; + _isPasswordValid = false; }); + return appLocalizationsOf(context).validationRequired; + } + + setState(() { + _isPasswordValid = true; + }); - return null; + return null; + }, + onFieldSubmitted: (_) async { + if (_isPasswordValid) { + PlausibleEventTracker.trackPressEnterContinueReturnUser(); + _onSubmit(); + } + }, + onChanged: (_) { + setState(() { + _isPasswordFailed = false; + }); + }, + errorMessage: 'Invalid password. Please try again.', + showErrorMessage: _isPasswordFailed, + ), + Align( + alignment: Alignment.center, + child: BiometricToggle( + padding: const EdgeInsets.only(top: 40), + onEnableBiometric: () { + context.read().add(const UnLockWithBiometrics()); }, - onFieldSubmitted: (_) async { + ), + ), + const Flexible(child: SizedBox(height: 40)), + ArDriveButtonNew( + text: 'Continue', + typography: typography, + variant: ButtonVariant.primary, + isDisabled: !_isPasswordValid || widget.checkingPassword, + onPressed: () { if (_isPasswordValid) { - PlausibleEventTracker.trackPressEnterContinueReturnUser(); + if (widget.alreadyLoggedIn) { + PlausibleEventTracker.trackClickContinueReturnUserButton(); + } else { + PlausibleEventTracker.trackClickContinueLoginButton(); + } + _onSubmit(); } - }, - onChanged: (_) { - setState(() { - _isPasswordFailed = false; - }); - }, - errorMessage: 'Invalid password. Please try again.', - showErrorMessage: _isPasswordFailed, - ), - Align( - alignment: Alignment.center, - child: BiometricToggle( - padding: const EdgeInsets.only(top: 40), - onEnableBiometric: () { - context.read().add(const UnLockWithBiometrics()); - }, + }), + if (widget.alreadyLoggedIn) ...[ + const SizedBox(height: 40), + Text.rich( + textAlign: TextAlign.center, + TextSpan( + children: [ + TextSpan( + // TODO: create/update localization key + text: appLocalizationsOf(context).forgetWallet, + style: typography.paragraphLarge( + color: colorTokens.textLow, + fontWeight: ArFontWeight.semiBold), + recognizer: TapGestureRecognizer() + ..onTap = () { + Navigator.of(context).pop(); + widget.loginBloc.add(const ForgetWallet()); + PlausibleEventTracker + .trackClickForgetWalletTextButton(); + }, + ), + ], ), - ), - const Flexible(child: SizedBox(height: 40)), - ArDriveButtonNew( - text: 'Continue', - typography: typography, - variant: ButtonVariant.primary, - isDisabled: !_isPasswordValid || widget.checkingPassword, - onPressed: () { - if (_isPasswordValid) { - if (widget.alreadyLoggedIn) { - PlausibleEventTracker - .trackClickContinueReturnUserButton(); - } else { - PlausibleEventTracker.trackClickContinueLoginButton(); - } - - _onSubmit(); - } - }), - if (widget.alreadyLoggedIn) ...[ - const SizedBox(height: 40), - Text.rich( - textAlign: TextAlign.center, - TextSpan( - children: [ - TextSpan( - // TODO: create/update localization key - text: appLocalizationsOf(context).forgetWallet, - style: typography.paragraphLarge( - color: colorTokens.textLow, - fontWeight: ArFontWeight.semiBold), - recognizer: TapGestureRecognizer() - ..onTap = () { - Navigator.of(context).pop(); - widget.loginBloc.add(const ForgetWallet()); - PlausibleEventTracker - .trackClickForgetWalletTextButton(); - }, - ), - ], - ), - ) - ], - if (isArioSDKSupportedOnPlatform()) - Padding( - padding: const EdgeInsets.only(top: 16.0), - child: ArDriveButtonNew( - variant: ButtonVariant.outline, - text: 'Advanced Settings', - maxHeight: 40, - typography: typography, - onPressed: () { - showGatewaySwitcherModal(context); - }, - ), - ) + ) ], - ), + // if (isArioSDKSupportedOnPlatform()) + // Padding( + // padding: const EdgeInsets.only(top: 16.0), + // child: ArDriveButtonNew( + // variant: ButtonVariant.outline, + // text: 'Advanced Settings', + // maxHeight: 40, + // typography: typography, + // onPressed: () { + // showGatewaySwitcherModal(context); + // }, + // ), + // ) + ], ), ); } @@ -313,3 +384,35 @@ void showEnterYourPasswordDialog( }, )); } + +class ForgetWalletDialog extends StatelessWidget { + const ForgetWalletDialog({super.key, required this.loginBloc}); + + final LoginBloc loginBloc; + + @override + Widget build(BuildContext context) { + return ArDriveStandardModalNew( + title: 'Forget wallet', + description: 'Are you sure you want to forget this wallet?', + actions: [ + ModalAction( + title: 'Cancel', + action: () { + Navigator.of(context).pop(); + }, + ), + ModalAction( + title: 'Confirm', + action: () { + Navigator.of(context).pop(); + Navigator.of(context).pop(); + loginBloc.add(const ForgetWallet()); + context.read().add(const CleanProfileName()); + PlausibleEventTracker.trackClickForgetWalletTextButton(); + }, + ), + ], + ); + } +} diff --git a/lib/blocs/fs_entry_preview/fs_entry_preview_cubit.dart b/lib/blocs/fs_entry_preview/fs_entry_preview_cubit.dart index 753c2c6061..f3fcb1605d 100644 --- a/lib/blocs/fs_entry_preview/fs_entry_preview_cubit.dart +++ b/lib/blocs/fs_entry_preview/fs_entry_preview_cubit.dart @@ -103,6 +103,13 @@ class FsEntryPreviewCubit extends Cubit { previewUrl, ); break; + case 'pdf': + _previewPdf( + fileKey != null, + selectedItem, + previewUrl, + ); + break; default: emit(FsEntryPreviewUnavailable()); @@ -112,6 +119,14 @@ class FsEntryPreviewCubit extends Cubit { } } + void _previewPdf( + bool isPrivate, + FileDataTableItem selectedItem, + String previewUrl, + ) { + emit(FsEntryPreviewUnavailable()); + } + Future _preview() async { final selectedItem = maybeSelectedItem; diff --git a/lib/blocs/fs_entry_preview/fs_entry_preview_state.dart b/lib/blocs/fs_entry_preview/fs_entry_preview_state.dart index e95b3a7e29..fb06cf79ee 100644 --- a/lib/blocs/fs_entry_preview/fs_entry_preview_state.dart +++ b/lib/blocs/fs_entry_preview/fs_entry_preview_state.dart @@ -31,6 +31,13 @@ class FsEntryPreviewImage extends FsEntryPreviewSuccess { List get props => [previewUrl]; } +class FsEntryPreviewPdf extends FsEntryPreviewSuccess { + const FsEntryPreviewPdf({required super.previewUrl}); + + @override + List get props => [previewUrl]; +} + class FsEntryPreviewAudio extends FsEntryPreviewSuccess { final String filename; const FsEntryPreviewAudio( diff --git a/lib/components/profile_card.dart b/lib/components/profile_card.dart index 6bcfc12b20..aee17d338f 100644 --- a/lib/components/profile_card.dart +++ b/lib/components/profile_card.dart @@ -664,11 +664,19 @@ class _ProfileMenuAccordionItem extends StatelessWidget { class ProfileCardHeader extends StatelessWidget { final String walletAddress; final VoidCallback onPressed; + final bool isExpanded; + final bool hasLogoutButton; + final Function()? onClickLogout; + final String? logoutTooltip; const ProfileCardHeader({ super.key, required this.walletAddress, required this.onPressed, + this.isExpanded = false, + this.hasLogoutButton = false, + this.onClickLogout, + this.logoutTooltip, }); @override @@ -677,22 +685,23 @@ class ProfileCardHeader extends StatelessWidget { return BlocBuilder( builder: (context, state) { + if (state.walletAddress == null || state.walletAddress!.isEmpty) { + return const SizedBox.shrink(); + } + final primaryName = _getPrimaryName(state, walletAddress); final maxWidth = _calculateMaxWidth(primaryName, state); final truncatedWalletAddress = _getTruncatedWalletAddress(primaryName, walletAddress); final tooltipMessage = primaryName.length > 20 ? primaryName : null; - return ArDriveTooltip( message: tooltipMessage ?? '', child: ArDriveButtonNew( text: primaryName, typography: typography, variant: ButtonVariant.outline, - content: state is ProfileNameLoaded - ? _buildLoadedContent(context, state, primaryName, - truncatedWalletAddress, maxWidth) - : null, + content: _buildLoadedContent( + context, state, primaryName, truncatedWalletAddress, maxWidth), maxWidth: maxWidth, maxHeight: state is ProfileNameLoaded ? 60 : 46, onPressed: onPressed, @@ -710,7 +719,7 @@ class ProfileCardHeader extends StatelessWidget { } double _calculateMaxWidth(String primaryName, ProfileNameState state) { - if (state is! ProfileNameLoaded) { + if (state is! ProfileNameLoaded && !isExpanded) { return 100; } @@ -720,9 +729,10 @@ class ProfileCardHeader extends StatelessWidget { } String _getTruncatedWalletAddress(String primaryName, String walletAddress) { - if (primaryName.length > 20) { + if (primaryName.length > 20 || isExpanded) { return truncateString(walletAddress, offsetStart: 10, offsetEnd: 10); } + var offsetStart = primaryName.length ~/ 2; var offsetEnd = primaryName.length ~/ 2; @@ -766,55 +776,123 @@ class ProfileCardHeader extends StatelessWidget { Widget _buildLoadedContent( BuildContext context, - ProfileNameLoaded state, + ProfileNameState state, String primaryName, String truncatedWalletAddress, double maxWidth, ) { final typography = ArDriveTypographyNew.of(context); final colorTokens = ArDriveTheme.of(context).themeData.colorTokens; + + if (state is! ProfileNameLoaded) { + return Center( + child: Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flexible( + child: Text( + isExpanded ? state.walletAddress! : truncatedWalletAddress, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: typography.paragraphNormal( + fontWeight: ArFontWeight.semiBold, + color: + isExpanded ? colorTokens.textLow : colorTokens.textHigh, + ), + ), + ), + if (hasLogoutButton) + Padding( + padding: const EdgeInsets.only(left: 16.0), + child: GestureDetector( + onTap: onClickLogout, + child: ArDriveClickArea( + tooltip: logoutTooltip, + child: ArDriveIcons.closeCircle( + size: 21, + color: colorTokens.iconLow, + ), + ), + ), + ), + ], + ), + ), + ); + } + final icon = _buildProfileIcon(state); return ConstrainedBox( - constraints: BoxConstraints(maxWidth: maxWidth), + constraints: isExpanded + ? const BoxConstraints(maxWidth: double.infinity) + : BoxConstraints(maxWidth: maxWidth), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - mainAxisSize: MainAxisSize.min, + mainAxisAlignment: isExpanded + ? MainAxisAlignment.spaceBetween + : MainAxisAlignment.spaceEvenly, + mainAxisSize: isExpanded ? MainAxisSize.max : MainAxisSize.min, children: [ - if (icon != null) icon, Flexible( - child: SizedBox( - height: 46, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Flexible( - child: Text( - primaryName, - overflow: TextOverflow.ellipsis, - maxLines: 1, - style: typography.paragraphLarge( - fontWeight: ArFontWeight.semiBold, - color: colorTokens.textHigh, - ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (icon != null) icon, + Flexible( + child: SizedBox( + height: 46, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Flexible( + child: Text( + primaryName, + overflow: TextOverflow.ellipsis, + maxLines: 1, + style: typography.paragraphLarge( + fontWeight: ArFontWeight.semiBold, + color: colorTokens.textHigh, + ), + ), + ), + Flexible( + child: Text( + isExpanded + ? state.walletAddress + : truncatedWalletAddress, + overflow: TextOverflow.clip, + maxLines: 1, + style: typography.paragraphSmall( + fontWeight: ArFontWeight.book, + color: colorTokens.textLow, + ), + ), + ), + ], ), ), - Flexible( - child: Text( - truncatedWalletAddress, - overflow: TextOverflow.clip, - maxLines: 1, - style: typography.paragraphSmall( - fontWeight: ArFontWeight.book, - color: colorTokens.textLow, - ), - ), + ), + ], + ), + ), + if (hasLogoutButton) + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: GestureDetector( + onTap: onClickLogout, + child: ArDriveClickArea( + tooltip: logoutTooltip, + child: ArDriveIcons.closeCircle( + size: 21, + color: colorTokens.iconLow, ), - ], + ), ), ), - ), ], ), ); diff --git a/lib/user/name/presentation/bloc/profile_name_bloc.dart b/lib/user/name/presentation/bloc/profile_name_bloc.dart index 38b3ec2727..a2d3b18fda 100644 --- a/lib/user/name/presentation/bloc/profile_name_bloc.dart +++ b/lib/user/name/presentation/bloc/profile_name_bloc.dart @@ -13,7 +13,7 @@ class ProfileNameBloc extends Bloc { final ArDriveAuth _auth; ProfileNameBloc(this._arnsRepository, this._auth) - : super(ProfileNameInitial(_auth.currentUser.walletAddress)) { + : super(const ProfileNameInitial(null)) { on((event, emit) async { await _loadProfileName( walletAddress: _auth.currentUser.walletAddress, @@ -28,12 +28,29 @@ class ProfileNameBloc extends Bloc { emit: emit, ); }); + on((event, emit) async { + emit(ProfileNameLoading(event.walletAddress)); + + logger + .d('Loading profile name for anonymous user ${event.walletAddress}'); + + await _loadProfileName( + walletAddress: event.walletAddress, + refresh: true, + emit: emit, + isUserLoggedIn: false, + ); + }); + on((event, emit) { + emit(const ProfileNameInitial(null)); + }); } Future _loadProfileName({ required String walletAddress, required bool refresh, required Emitter emit, + bool isUserLoggedIn = true, }) async { try { /// if we are not refreshing, we emit a loading state @@ -44,7 +61,7 @@ class ProfileNameBloc extends Bloc { final primaryName = await _arnsRepository.getPrimaryName(walletAddress, update: refresh); - if (_auth.currentUser.walletAddress != walletAddress) { + if (isUserLoggedIn && _auth.currentUser.walletAddress != walletAddress) { // A user can load profile name and log out while fetching this request. Then log in again. We should not emit a profile name loaded state in this case. logger.d('User logged out while fetching profile name'); diff --git a/lib/user/name/presentation/bloc/profile_name_event.dart b/lib/user/name/presentation/bloc/profile_name_event.dart index 64b04c2339..23e2135ab0 100644 --- a/lib/user/name/presentation/bloc/profile_name_event.dart +++ b/lib/user/name/presentation/bloc/profile_name_event.dart @@ -10,3 +10,13 @@ sealed class ProfileNameEvent extends Equatable { final class RefreshProfileName extends ProfileNameEvent {} final class LoadProfileName extends ProfileNameEvent {} + +final class LoadProfileNameAnonymous extends ProfileNameEvent { + final String walletAddress; + + const LoadProfileNameAnonymous(this.walletAddress); +} + +final class CleanProfileName extends ProfileNameEvent { + const CleanProfileName(); +} diff --git a/lib/user/name/presentation/bloc/profile_name_state.dart b/lib/user/name/presentation/bloc/profile_name_state.dart index c3ec41d0d6..a8534e7a31 100644 --- a/lib/user/name/presentation/bloc/profile_name_state.dart +++ b/lib/user/name/presentation/bloc/profile_name_state.dart @@ -3,7 +3,7 @@ part of 'profile_name_bloc.dart'; sealed class ProfileNameState extends Equatable { const ProfileNameState(); - abstract final String walletAddress; + abstract final String? walletAddress; @override List get props => []; @@ -13,7 +13,7 @@ final class ProfileNameInitial extends ProfileNameState { const ProfileNameInitial(this.walletAddress); @override - final String walletAddress; + final String? walletAddress; } final class ProfileNameLoading extends ProfileNameState {