diff --git a/lib/core/exchange/domain/usecases/create_log_attachment_usecase.dart b/lib/core/exchange/domain/usecases/create_log_attachment_usecase.dart new file mode 100644 index 000000000..a9b498d3e --- /dev/null +++ b/lib/core/exchange/domain/usecases/create_log_attachment_usecase.dart @@ -0,0 +1,62 @@ +import 'dart:convert'; +import 'dart:math'; +import 'dart:typed_data'; + +import 'package:bb_mobile/core/errors/bull_exception.dart'; +import 'package:bb_mobile/core/exchange/domain/entity/support_chat_message_attachment.dart'; +import 'package:bb_mobile/core/utils/logger.dart'; +import 'package:intl/intl.dart'; + +class CreateLogAttachmentUsecase { + Future execute() async { + try { + List logs; + try { + logs = await log.readLogs(); + } catch (e) { + logs = [ + 'timestamp\tlevel\tmessage\terror\ttrace', + '${DateTime.now().toIso8601String()}\tINFO\tNo logs file found or logs could not be read: $e\t\t', + ]; + } + + if (logs.isEmpty) { + logs = [ + 'timestamp\tlevel\tmessage\terror\ttrace', + '${DateTime.now().toIso8601String()}\tINFO\tNo logs have been recorded yet\t\t', + ]; + } + + final logContent = logs.join('\n'); + final bytes = Uint8List.fromList(utf8.encode(logContent)); + + final random = Random(); + final timestamp = DateFormat('yyyyMMdd_HHmmss').format(DateTime.now()); + + const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + final randomAlphanumeric = String.fromCharCodes( + Iterable.generate( + 8, + (_) => chars.codeUnitAt(random.nextInt(chars.length)), + ), + ); + + final fileName = '$timestamp.BullLog.$randomAlphanumeric.txt'; + + return SupportChatMessageAttachment( + attachmentId: 'temp_logs_${DateTime.now().millisecondsSinceEpoch}', + fileName: fileName, + fileType: 'text/plain', + fileSize: bytes.length, + fileData: bytes, + createdAt: DateTime.now(), + ); + } catch (e) { + throw CreateLogAttachmentException('$e'); + } + } +} + +class CreateLogAttachmentException extends BullException { + CreateLogAttachmentException(super.message); +} diff --git a/lib/core/exchange/exchange_locator.dart b/lib/core/exchange/exchange_locator.dart index 160384dd7..fbcd89bb2 100644 --- a/lib/core/exchange/exchange_locator.dart +++ b/lib/core/exchange/exchange_locator.dart @@ -19,6 +19,7 @@ import 'package:bb_mobile/core/exchange/domain/repositories/exchange_user_reposi import 'package:bb_mobile/core/exchange/domain/repositories/price_repository.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/convert_currency_to_sats_amount_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/convert_sats_to_currency_amount_usecase.dart'; +import 'package:bb_mobile/core/exchange/domain/usecases/create_log_attachment_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/delete_exchange_api_key_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/get_available_currencies_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/get_exchange_funding_details_usecase.dart'; @@ -462,6 +463,10 @@ class ExchangeLocator { ), ); + locator.registerFactory( + () => CreateLogAttachmentUsecase(), + ); + locator.registerFactory( () => LabelExchangeOrdersUsecase( labelDatasource: locator(), diff --git a/lib/features/buy/ui/screens/buy_confirm_screen.dart b/lib/features/buy/ui/screens/buy_confirm_screen.dart index 85ce1285e..e3240e003 100644 --- a/lib/features/buy/ui/screens/buy_confirm_screen.dart +++ b/lib/features/buy/ui/screens/buy_confirm_screen.dart @@ -78,7 +78,7 @@ class BuyConfirmScreen extends StatelessWidget { child: BBText( formattedPayInAmount, style: context.font.displaySmall, - color: context.appColors.outlineVariant, + color: context.appColors.secondary, ), ), const Gap(32), @@ -142,7 +142,7 @@ class BuyConfirmScreen extends StatelessWidget { context.read().add(const BuyEvent.confirmOrder()); }, bgColor: context.appColors.secondary, - textColor: context.appColors.onPrimary, + textColor: context.appColors.onSecondary, ), ], ), diff --git a/lib/features/buy/ui/widgets/buy_amount_input_fields.dart b/lib/features/buy/ui/widgets/buy_amount_input_fields.dart index 9c2f0f069..5461d7f85 100644 --- a/lib/features/buy/ui/widgets/buy_amount_input_fields.dart +++ b/lib/features/buy/ui/widgets/buy_amount_input_fields.dart @@ -83,7 +83,7 @@ class _BuyAmountInputFieldsState extends State { mainAxisSize: .min, mainAxisAlignment: .spaceBetween, children: [ - Expanded( + Expanded( child: TextFormField( controller: _amountController, keyboardType: const TextInputType.numberWithOptions( @@ -109,7 +109,7 @@ class _BuyAmountInputFieldsState extends State { decimalDigits: amountInputDecimals, ).format(0), hintStyle: context.font.displaySmall?.copyWith( - color: context.appColors.primary, + color: context.appColors.onSurfaceVariant, ), border: InputBorder.none, ), @@ -229,7 +229,9 @@ class _BuyAmountInputFieldsState extends State { value: currencyCode, child: Text( '$currencyCode Balance - ${FormatAmount.fiat(balances[currencyCode] ?? 0, currencyCode, simpleFormat: true)}', - style: context.font.headlineSmall, + style: context.font.headlineSmall?.copyWith( + color: context.appColors.secondary, + ), ), ), ) diff --git a/lib/features/buy/ui/widgets/buy_confirm_detail_row.dart b/lib/features/buy/ui/widgets/buy_confirm_detail_row.dart index 81d8afecd..7b9cc1e20 100644 --- a/lib/features/buy/ui/widgets/buy_confirm_detail_row.dart +++ b/lib/features/buy/ui/widgets/buy_confirm_detail_row.dart @@ -20,7 +20,7 @@ class BuyConfirmDetailRow extends StatelessWidget { Text( label, style: theme.textTheme.bodyMedium?.copyWith( - color: context.appColors.surfaceContainer, + color: context.appColors.onSurfaceVariant, ), ), @@ -32,7 +32,7 @@ class BuyConfirmDetailRow extends StatelessWidget { value!, textAlign: .end, style: theme.textTheme.bodyMedium?.copyWith( - color: context.appColors.outlineVariant, + color: context.appColors.secondary, ), ), ), diff --git a/lib/features/buy/ui/widgets/buy_destination_input_fields.dart b/lib/features/buy/ui/widgets/buy_destination_input_fields.dart index 12e645061..3d5cf8370 100644 --- a/lib/features/buy/ui/widgets/buy_destination_input_fields.dart +++ b/lib/features/buy/ui/widgets/buy_destination_input_fields.dart @@ -79,15 +79,20 @@ class _BuyDestinationInputFieldsState extends State { final label = w.displayLabel(context); return DropdownMenuItem( value: w.id, - child: Text(label, style: context.font.headlineSmall), + child: Text( + label, + style: context.font.headlineSmall?.copyWith( + color: context.appColors.secondary, + ), + ), ); }), DropdownMenuItem( child: Text( - // To not show the external wallet label before the wallets - // are loaded return an empty string if not started up. !isStarted ? '' : externalBitcoinWalletLabel, - style: context.font.headlineSmall, + style: context.font.headlineSmall?.copyWith( + color: context.appColors.secondary, + ), ), ), ], @@ -117,17 +122,19 @@ class _BuyDestinationInputFieldsState extends State { height: 56, child: Material( elevation: 2, - color: context.appColors.secondary, + color: context.appColors.onSecondary, borderRadius: BorderRadius.circular(2.0), child: Center( child: TextFormField( controller: _bitcoinAddressInputController, textAlignVertical: TextAlignVertical.center, - style: context.font.headlineSmall, + style: context.font.headlineSmall?.copyWith( + color: context.appColors.secondary, + ), decoration: InputDecoration( hintText: context.loc.buyBitcoinAddressHint, hintStyle: context.font.headlineSmall?.copyWith( - color: context.appColors.outline, + color: context.appColors.onSurfaceVariant, ), border: InputBorder.none, contentPadding: const EdgeInsets.symmetric( diff --git a/lib/features/exchange/ui/exchange_router.dart b/lib/features/exchange/ui/exchange_router.dart index 419b01e2f..d4d0ab94b 100644 --- a/lib/features/exchange/ui/exchange_router.dart +++ b/lib/features/exchange/ui/exchange_router.dart @@ -7,6 +7,7 @@ import 'package:bb_mobile/features/exchange/ui/screens/exchange_home_screen.dart import 'package:bb_mobile/features/exchange/ui/screens/exchange_kyc_screen.dart'; import 'package:bb_mobile/features/exchange/ui/screens/exchange_landing_screen.dart'; import 'package:bb_mobile/features/exchange/ui/screens/exchange_landing_screen_v2.dart'; +import 'package:bb_mobile/features/exchange/ui/screens/exchange_support_login_screen.dart'; import 'package:bb_mobile/features/exchange_support_chat/ui/exchange_support_chat_router.dart'; import 'package:bb_mobile/features/settings/presentation/bloc/settings_cubit.dart'; import 'package:flutter/material.dart'; @@ -16,6 +17,7 @@ import 'package:go_router/go_router.dart'; enum ExchangeRoute { exchangeHome('/exchange'), exchangeLanding('/exchange/landing'), + exchangeLoginForSupport('/exchange/login-support'), exchangeAuth('/exchange/auth'), exchangeKyc('kyc'); @@ -74,6 +76,23 @@ class ExchangeRouter { return NoTransitionPage(key: state.pageKey, child: landingScreen); }, ), + GoRoute( + name: ExchangeRoute.exchangeLoginForSupport.name, + path: ExchangeRoute.exchangeLoginForSupport.path, + pageBuilder: (context, state) { + Widget screen; + if (Platform.isIOS) { + final isSuperuser = + context.read().state.isSuperuser ?? false; + screen = isSuperuser + ? const ExchangeLandingScreen() + : const ExchangeSupportLoginScreen(); + } else { + screen = const ExchangeLandingScreen(); + } + return NoTransitionPage(key: state.pageKey, child: screen); + }, + ), GoRoute( name: ExchangeRoute.exchangeAuth.name, path: ExchangeRoute.exchangeAuth.path, @@ -81,9 +100,8 @@ class ExchangeRouter { return NoTransitionPage( key: state.pageKey, child: BlocListener( - listenWhen: - (previous, current) => - previous.notLoggedIn && !current.notLoggedIn, + listenWhen: (previous, current) => + previous.notLoggedIn && !current.notLoggedIn, listener: (context, state) { // Redirect to home screen if the API key becomes valid context.goNamed(ExchangeRoute.exchangeHome.name); diff --git a/lib/features/exchange/ui/screens/exchange_home_screen.dart b/lib/features/exchange/ui/screens/exchange_home_screen.dart index acece3e0c..c535a0e44 100644 --- a/lib/features/exchange/ui/screens/exchange_home_screen.dart +++ b/lib/features/exchange/ui/screens/exchange_home_screen.dart @@ -4,6 +4,7 @@ import 'package:bb_mobile/core/widgets/buttons/button.dart'; import 'package:bb_mobile/core/widgets/navbar/top_bar_bull_logo.dart'; import 'package:bb_mobile/features/bitcoin_price/presentation/cubit/price_chart_cubit.dart'; import 'package:bb_mobile/features/exchange/presentation/exchange_cubit.dart'; +import 'package:bb_mobile/features/exchange/ui/exchange_router.dart'; import 'package:bb_mobile/features/exchange/ui/widgets/dca_list_tile.dart'; import 'package:bb_mobile/features/exchange/ui/widgets/exchange_home_kyc_card.dart'; import 'package:bb_mobile/features/exchange/ui/widgets/exchange_home_top_section.dart'; @@ -87,10 +88,6 @@ class ExchangeHomeScreen extends StatelessWidget { BlocBuilder( builder: (context, priceChartState) { final showChart = priceChartState.showChart; - final hasApiKey = context.select( - (ExchangeCubit cubit) => - cubit.state.apiKeyException == null, - ); return SliverAppBar( backgroundColor: Colors.transparent, @@ -113,7 +110,7 @@ class ExchangeHomeScreen extends StatelessWidget { }, ) : SizedBox( - width: hasApiKey ? 96 : 48, + width: 96, child: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -132,29 +129,40 @@ class ExchangeHomeScreen extends StatelessWidget { .showChart(); }, ), - if (hasApiKey) - IconButton( - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - visualDensity: VisualDensity.compact, - icon: Icon( - Icons.chat_bubble_outline, - color: context.appColors.onPrimary, - size: 24, - ), - onPressed: () { + IconButton( + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + visualDensity: VisualDensity.compact, + icon: Icon( + Icons.chat_bubble_outline, + color: context.appColors.onPrimary, + size: 24, + ), + onPressed: () { + final notLoggedIn = context + .read() + .state + .notLoggedIn; + if (notLoggedIn) { + context.pushNamed( + ExchangeRoute + .exchangeLoginForSupport + .name, + ); + } else { context.pushNamed( ExchangeSupportChatRoute .supportChat .name, ); - }, - ), + } + }, + ), ], ), ), ), - leadingWidth: showChart ? 56 : (hasApiKey ? 112 : 56), + leadingWidth: showChart ? 56 : 112, actionsIconTheme: IconThemeData( color: context.appColors.onPrimary, size: 24, diff --git a/lib/features/exchange/ui/screens/exchange_landing_screen_v2.dart b/lib/features/exchange/ui/screens/exchange_landing_screen_v2.dart index e87683261..ff551695e 100644 --- a/lib/features/exchange/ui/screens/exchange_landing_screen_v2.dart +++ b/lib/features/exchange/ui/screens/exchange_landing_screen_v2.dart @@ -25,10 +25,11 @@ class ExchangeLandingScreenV2 extends StatelessWidget { context.goNamed(WalletRoute.walletHome.name); }, child: Scaffold( - backgroundColor: context.appColors.secondary, + backgroundColor: context.appColors.secondaryFixed, appBar: AppBar( + backgroundColor: Colors.transparent, leading: BackButton( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, onPressed: () => context.goNamed(WalletRoute.walletHome.name), ), ), @@ -37,10 +38,7 @@ class ExchangeLandingScreenV2 extends StatelessWidget { children: [ // Background image with geometric pattern Positioned.fill( - child: Image.asset( - Assets.backgrounds.bgLong.path, - fit: .cover, - ), + child: Image.asset(Assets.backgrounds.bgLong.path, fit: .cover), ), SingleChildScrollView( padding: const EdgeInsets.all(24.0), @@ -59,7 +57,7 @@ class ExchangeLandingScreenV2 extends StatelessWidget { BBText( context.loc.exchangeBrandName, style: AppFonts.textTitleTheme.textStyle.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, fontSize: 64, ), ), @@ -67,7 +65,7 @@ class ExchangeLandingScreenV2 extends StatelessWidget { BBText( context.loc.exchangeLandingRecommendedExchange, style: context.font.headlineSmall?.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, ), ), ], @@ -90,42 +88,42 @@ class ExchangeLandingScreenV2 extends StatelessWidget { BBText( context.loc.exchangeFeatureSelfCustody, style: context.font.bodyLarge?.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, ), ), const Gap(12), BBText( context.loc.exchangeFeatureDcaOrders, style: context.font.bodyLarge?.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, ), ), const Gap(12), BBText( context.loc.exchangeFeatureSellBitcoin, style: context.font.bodyLarge?.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, ), ), const Gap(12), BBText( context.loc.exchangeFeatureBankTransfers, style: context.font.bodyLarge?.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, ), ), const Gap(12), BBText( context.loc.exchangeFeatureCustomerSupport, style: context.font.bodyLarge?.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, ), ), const Gap(12), BBText( context.loc.exchangeFeatureUnifiedHistory, style: context.font.bodyLarge?.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, ), ), ], @@ -144,7 +142,7 @@ class ExchangeLandingScreenV2 extends StatelessWidget { children: [ Icon( Icons.info_outline, - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, size: 20, ), const Gap(8), @@ -157,7 +155,7 @@ class ExchangeLandingScreenV2 extends StatelessWidget { .loc .exchangeLandingDisclaimerNotAvailable, style: context.font.bodySmall?.copyWith( - color: context.appColors.onSecondary, + color: context.appColors.onSecondaryFixed, ), ), ], @@ -184,7 +182,7 @@ class ExchangeLandingScreenV2 extends StatelessWidget { } }, bgColor: context.appColors.primary, - textColor: context.appColors.onSecondary, + textColor: context.appColors.onSecondaryFixed, ), ), const Gap(32), diff --git a/lib/features/exchange/ui/screens/exchange_support_login_screen.dart b/lib/features/exchange/ui/screens/exchange_support_login_screen.dart new file mode 100644 index 000000000..0be9a6690 --- /dev/null +++ b/lib/features/exchange/ui/screens/exchange_support_login_screen.dart @@ -0,0 +1,128 @@ +import 'package:bb_mobile/core/themes/app_theme.dart'; +import 'package:bb_mobile/core/themes/fonts.dart'; +import 'package:bb_mobile/core/utils/build_context_x.dart'; +import 'package:bb_mobile/core/widgets/buttons/button.dart'; +import 'package:bb_mobile/core/widgets/text/text.dart'; +import 'package:bb_mobile/features/exchange/ui/exchange_router.dart'; +import 'package:bb_mobile/features/wallet/ui/wallet_router.dart'; +import 'package:bb_mobile/generated/flutter_gen/assets.gen.dart'; +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; + +class ExchangeSupportLoginScreen extends StatelessWidget { + const ExchangeSupportLoginScreen({super.key}); + + @override + Widget build(BuildContext context) { + return PopScope( + canPop: false, + onPopInvokedWithResult: (didPop, _) { + if (didPop) return; + context.goNamed(WalletRoute.walletHome.name); + }, + child: Scaffold( + backgroundColor: context.appColors.background, + appBar: AppBar( + leading: BackButton( + color: context.appColors.onSurface, + onPressed: () => context.goNamed(WalletRoute.walletHome.name), + ), + ), + extendBodyBehindAppBar: true, + body: SingleChildScrollView( + padding: const EdgeInsets.all(24.0), + child: Column( + children: [ + const Gap(32), + Center( + child: Column( + children: [ + Image.asset( + Assets.logos.bbLogoSmall.path, + width: 120, + height: 120, + ), + const Gap(16), + BBText( + context.loc.exchangeBrandName, + style: AppFonts.textTitleTheme.textStyle.copyWith( + color: context.appColors.primary, + fontSize: 64, + ), + ), + const Gap(12), + BBText( + context.loc.exchangeSupportLoginSubtitle, + style: context.font.headlineSmall?.copyWith( + color: context.appColors.onSurface, + ), + ), + ], + ), + ), + const Gap(32), + Container( + padding: const EdgeInsets.all(32), + decoration: BoxDecoration( + color: context.appColors.surfaceContainer, + border: Border.all( + color: context.appColors.outline, + width: 0, + ), + borderRadius: BorderRadius.circular(12), + ), + child: BBText( + context.loc.exchangeSupportLoginAccessMessage, + style: context.font.bodyLarge?.copyWith( + color: context.appColors.onSurface, + ), + ), + ), + const Gap(16), + Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + color: context.appColors.surfaceContainer, + borderRadius: BorderRadius.circular(8), + ), + child: Row( + crossAxisAlignment: .start, + children: [ + Icon( + Icons.info_outline, + color: context.appColors.primary, + size: 20, + ), + const Gap(8), + Expanded( + child: BBText( + context.loc.exchangeSupportLoginAccountInfo, + style: context.font.bodySmall?.copyWith( + color: context.appColors.onSurface, + ), + ), + ), + ], + ), + ), + const Gap(40), + SizedBox( + width: double.infinity, + child: BBButton.big( + label: context.loc.exchangeLoginButton, + onPressed: () { + context.goNamed(ExchangeRoute.exchangeAuth.name); + }, + bgColor: context.appColors.primary, + textColor: context.appColors.onPrimary, + ), + ), + const Gap(32), + ], + ), + ), + ), + ); + } +} diff --git a/lib/features/exchange_support_chat/presentation/exchange_support_chat_cubit.dart b/lib/features/exchange_support_chat/presentation/exchange_support_chat_cubit.dart index a51775559..68bb8cd46 100644 --- a/lib/features/exchange_support_chat/presentation/exchange_support_chat_cubit.dart +++ b/lib/features/exchange_support_chat/presentation/exchange_support_chat_cubit.dart @@ -1,9 +1,11 @@ import 'dart:io'; + import 'package:bb_mobile/core/exchange/domain/entity/support_chat_message.dart'; import 'package:bb_mobile/core/exchange/domain/entity/support_chat_message_attachment.dart'; +import 'package:bb_mobile/core/exchange/domain/usecases/create_log_attachment_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/get_exchange_user_summary_usecase.dart'; -import 'package:bb_mobile/core/exchange/domain/usecases/get_support_chat_messages_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/get_support_chat_message_attachment_usecase.dart'; +import 'package:bb_mobile/core/exchange/domain/usecases/get_support_chat_messages_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/send_support_chat_message_usecase.dart'; import 'package:bb_mobile/features/exchange_support_chat/presentation/exchange_support_chat_state.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -18,16 +20,19 @@ class ExchangeSupportChatCubit extends Cubit { required SendSupportChatMessageUsecase sendMessageUsecase, required GetSupportChatMessageAttachmentUsecase getAttachmentUsecase, required GetExchangeUserSummaryUsecase getUserSummaryUsecase, + required CreateLogAttachmentUsecase createLogAttachmentUsecase, }) : _getMessagesUsecase = getMessagesUsecase, _sendMessageUsecase = sendMessageUsecase, _getAttachmentUsecase = getAttachmentUsecase, _getUserSummaryUsecase = getUserSummaryUsecase, + _createLogAttachmentUsecase = createLogAttachmentUsecase, super(const ExchangeSupportChatState()); final GetSupportChatMessagesUsecase _getMessagesUsecase; final SendSupportChatMessageUsecase _sendMessageUsecase; final GetSupportChatMessageAttachmentUsecase _getAttachmentUsecase; final GetExchangeUserSummaryUsecase _getUserSummaryUsecase; + final CreateLogAttachmentUsecase _createLogAttachmentUsecase; bool _limitFetchingOlderMessages = false; @@ -276,6 +281,27 @@ class ExchangeSupportChatCubit extends Cubit { ); } + Future attachLogs() async { + try { + emit(state.copyWith(errorPermissionDenied: '')); + + final attachment = await _createLogAttachmentUsecase.execute(); + + emit( + state.copyWith( + newMessageText: 'Here are my logs', + newMessageAttachments: [...state.newMessageAttachments, attachment], + ), + ); + } catch (e) { + emit( + state.copyWith( + errorPermissionDenied: 'Failed to attach logs. Please try again.', + ), + ); + } + } + Future downloadAttachment(String attachmentId) async { try { emit( @@ -354,6 +380,9 @@ class ExchangeSupportChatCubit extends Cubit { attachments: hasAttachments ? attachmentsToSend : null, ); + // Don't immediately reload - let the message appear naturally + // The attachment might not be fully processed on the server yet + await Future.delayed(const Duration(seconds: 2)); await loadMessages(page: 1); emit(state.copyWith(sendingMessage: false)); diff --git a/lib/features/exchange_support_chat/ui/screens/exchange_support_chat_screen.dart b/lib/features/exchange_support_chat/ui/screens/exchange_support_chat_screen.dart index f21c15967..f36e52b8f 100644 --- a/lib/features/exchange_support_chat/ui/screens/exchange_support_chat_screen.dart +++ b/lib/features/exchange_support_chat/ui/screens/exchange_support_chat_screen.dart @@ -1,14 +1,13 @@ import 'package:bb_mobile/core/exchange/domain/entity/support_chat_message.dart'; import 'package:bb_mobile/core/exchange/domain/entity/support_chat_message_attachment.dart'; +import 'package:bb_mobile/core/exchange/domain/usecases/create_log_attachment_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/get_exchange_user_summary_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/get_support_chat_message_attachment_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/get_support_chat_messages_usecase.dart'; import 'package:bb_mobile/core/exchange/domain/usecases/send_support_chat_message_usecase.dart'; import 'package:bb_mobile/core/themes/app_theme.dart'; import 'package:bb_mobile/core/utils/build_context_x.dart'; -import 'package:bb_mobile/core/utils/constants.dart'; import 'package:bb_mobile/core/widgets/buttons/button.dart'; -import 'package:bb_mobile/core/widgets/cards/info_card.dart'; import 'package:bb_mobile/core/widgets/inputs/text_input.dart'; import 'package:bb_mobile/core/widgets/snackbar_utils.dart'; import 'package:bb_mobile/core/widgets/text/text.dart'; @@ -19,7 +18,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:gap/gap.dart'; import 'package:intl/intl.dart'; -import 'package:url_launcher/url_launcher.dart'; class ExchangeSupportChatScreen extends StatelessWidget { const ExchangeSupportChatScreen({super.key}); @@ -32,6 +30,7 @@ class ExchangeSupportChatScreen extends StatelessWidget { sendMessageUsecase: locator(), getAttachmentUsecase: locator(), getUserSummaryUsecase: locator(), + createLogAttachmentUsecase: locator(), )..loadMessages(), child: Scaffold( appBar: AppBar( @@ -91,20 +90,6 @@ class _ChatBodyState extends State<_ChatBody> { Widget build(BuildContext context) { return Column( children: [ - Padding( - padding: const EdgeInsets.all(16), - child: InfoCard( - description: context.loc.exchangeSupportChatWalletIssuesInfo, - tagColor: context.appColors.primary, - bgColor: context.appColors.surfaceContainer, - onTap: () async { - final Uri url = Uri.parse(SettingsConstants.telegramSupportLink); - if (await canLaunchUrl(url)) { - await launchUrl(url, mode: LaunchMode.externalApplication); - } - }, - ), - ), Expanded( child: BlocConsumer( @@ -367,6 +352,23 @@ class _MessageInputState extends State<_MessageInput> { ), ), const Gap(8), + SizedBox( + width: 52, + height: 52, + child: BBButton.big( + label: '', + iconData: Icons.description, + disabled: false, + onPressed: () { + context.read().attachLogs(); + }, + bgColor: context.appColors.surfaceContainer, + textColor: context.appColors.onSurface, + width: 52, + height: 52, + ), + ), + const Gap(8), Expanded( child: BBInputText( value: state.newMessageText, @@ -441,6 +443,7 @@ class _AttachmentWidget extends StatelessWidget { Widget build(BuildContext context) { final isImage = attachment.fileType?.startsWith('image/') ?? false; final isPdf = attachment.fileType == 'application/pdf'; + final isLog = attachment.fileName?.contains('.BullLog.') ?? false; final isLoading = context.select( (ExchangeSupportChatCubit cubit) => cubit.state.loadingAttachmentId == attachment.attachmentId, @@ -559,6 +562,14 @@ class _AttachmentWidget extends StatelessWidget { ? context.appColors.onSecondary : context.appColors.secondary, ) + else if (isLog) + Icon( + Icons.description, + size: 30, + color: isUserMessage + ? context.appColors.onSecondary + : context.appColors.secondary, + ) else Icon( Icons.file_present, @@ -618,6 +629,7 @@ class _AttachmentPreviewWidget extends StatelessWidget { Widget build(BuildContext context) { final isImage = attachment.fileType?.startsWith('image/') ?? false; final isPdf = attachment.fileType == 'application/pdf'; + final isLog = attachment.fileName?.contains('.BullLog.') ?? false; return Stack( children: [ @@ -645,6 +657,8 @@ class _AttachmentPreviewWidget extends StatelessWidget { ) : isPdf ? const Icon(Icons.picture_as_pdf) + : isLog + ? const Icon(Icons.description) : const Icon(Icons.file_present), ), Positioned( diff --git a/lib/features/wallet/ui/widgets/wallet_home_app_bar.dart b/lib/features/wallet/ui/widgets/wallet_home_app_bar.dart index 8123eb720..aaa030d8f 100644 --- a/lib/features/wallet/ui/widgets/wallet_home_app_bar.dart +++ b/lib/features/wallet/ui/widgets/wallet_home_app_bar.dart @@ -2,6 +2,7 @@ import 'package:bb_mobile/core/themes/app_theme.dart'; import 'package:bb_mobile/core/widgets/navbar/top_bar_bull_logo.dart'; import 'package:bb_mobile/features/bitcoin_price/presentation/cubit/price_chart_cubit.dart'; import 'package:bb_mobile/features/exchange/presentation/exchange_cubit.dart'; +import 'package:bb_mobile/features/exchange/ui/exchange_router.dart'; import 'package:bb_mobile/features/exchange_support_chat/ui/exchange_support_chat_router.dart'; import 'package:bb_mobile/features/settings/ui/settings_router.dart'; import 'package:bb_mobile/features/transactions/ui/transactions_router.dart'; @@ -40,9 +41,6 @@ class _WalletHomeAppBarState extends State { final showChart = context.select( (PriceChartCubit cubit) => cubit.state.showChart, ); - final hasApiKey = context.select( - (ExchangeCubit cubit) => cubit.state.apiKeyException == null, - ); return AppBar( backgroundColor: context.appColors.transparent, @@ -68,7 +66,7 @@ class _WalletHomeAppBarState extends State { }, ) : SizedBox( - width: hasApiKey ? 96 : 48, + width: 96, child: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -85,27 +83,36 @@ class _WalletHomeAppBarState extends State { context.read().showChart(); }, ), - if (hasApiKey) - IconButton( - padding: EdgeInsets.zero, - constraints: const BoxConstraints(), - visualDensity: VisualDensity.compact, - icon: Icon( - Icons.chat_bubble_outline, - color: context.appColors.onPrimary, - size: 24, - ), - onPressed: () { + IconButton( + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + visualDensity: VisualDensity.compact, + icon: Icon( + Icons.chat_bubble_outline, + color: context.appColors.onPrimary, + size: 24, + ), + onPressed: () { + final notLoggedIn = context + .read() + .state + .notLoggedIn; + if (notLoggedIn) { + context.pushNamed( + ExchangeRoute.exchangeLoginForSupport.name, + ); + } else { context.pushNamed( ExchangeSupportChatRoute.supportChat.name, ); - }, - ), + } + }, + ), ], ), ), ), - leadingWidth: showChart ? 56 : (hasApiKey ? 112 : 56), + leadingWidth: showChart ? 56 : 112, actionsIconTheme: IconThemeData( color: context.appColors.onPrimary, size: 24, diff --git a/localization/app_de.arb b/localization/app_de.arb index 14939f057..ed2d244be 100644 --- a/localization/app_de.arb +++ b/localization/app_de.arb @@ -489,7 +489,7 @@ "paySelectRecipient": "Wählen Sie Empfänger", "payNoActiveWallet": "Keine aktive Brieftasche", "importQrDeviceKruxStep4": "Klicken Sie auf die Schaltfläche \"Kamera öffnen\"", - "appStartupErrorMessageWithBackup": "Auf v5.4.0 wurde ein kritischer Fehler in einer unserer Abhängigkeiten entdeckt, die die private Schlüsselspeicherung beeinflussen. Ihre App wurde dadurch beeinflusst. Sie müssen diese App löschen und sie mit Ihrem gesicherten Saatgut neu installieren.", + "appStartupErrorMessageWithBackup": "Konnte nicht initialisiert werden. Löschen und neu installieren, um zu beheben.", "payPasteInvoice": "Paste Invoice", "labelErrorUnexpected": "Unerwartete Fehler: {message}", "@labelErrorUnexpected": { @@ -1721,7 +1721,7 @@ "fundExchangeRegularSepaInfo": "Nur für Transaktionen über 20.000 €. Für kleinere Transaktionen verwenden Sie die Instant SEPA Option.", "fundExchangeDoneButton": "KAPITEL", "buyKYCLevel3": "Ebene 3 - Voll", - "appStartupErrorMessageNoBackup": "Auf v5.4.0 wurde ein kritischer Fehler in einer unserer Abhängigkeiten entdeckt, die die private Schlüsselspeicherung beeinflussen. Ihre App wurde dadurch beeinflusst. Kontaktieren Sie unser Support-Team.", + "appStartupErrorMessageNoBackup": "Konnte nicht initialisiert werden. Löschen und neu installieren, um zu beheben. Wenn Ihr Seed nicht gesichert ist, können Sie ihn nach der Neuinstallation unter Einstellungen->Bitcoin-Einstellungen->Seeds anzeigen anzeigen.", "sellGoHome": "Geh nach Hause", "keystoneStep8": "Sobald die Transaktion in Ihrem Keystone importiert wird, überprüfen Sie die Zieladresse und den Betrag.", "psbtFlowSpecterTitle": "Musteranleitung", @@ -3339,6 +3339,10 @@ }, "payInvoiceDetails": "Invoice Details", "exchangeLandingLoginButton": "Anmelden oder Anmelden", + "exchangeLandingLoginToUseSupport": "Bitte melden Sie sich an oder registrieren Sie sich, um den Support-Chat für Börsenfragen zu nutzen.", + "exchangeSupportLoginSubtitle": "Mit Bull Bitcoin Support-Konto verbinden", + "exchangeSupportLoginAccessMessage": "Sie haben nur Zugriff auf die Support-Chat-Funktion.", + "exchangeSupportLoginAccountInfo": "Sie erstellen ein Konto bei bullbitcoin.com, auf das Sie jederzeit über unsere Web-App zugreifen können.", "torSettingsEnableProxy": "Tor Proxy aktivieren", "bitboxScreenAddressToVerify": "Anschrift:", "payConfirmPayment": "Zahlung bestätigen", diff --git a/localization/app_en.arb b/localization/app_en.arb index 43209e061..e406f873b 100644 --- a/localization/app_en.arb +++ b/localization/app_en.arb @@ -9972,6 +9972,22 @@ "@exchangeLandingLoginButton": { "description": "Button to proceed to login/signup" }, + "exchangeLandingLoginToUseSupport": "Please login or sign up to use the support chat for exchange related issues.", + "@exchangeLandingLoginToUseSupport": { + "description": "Message prompting user to login to access support chat" + }, + "exchangeSupportLoginSubtitle": "Connect to Bull Bitcoin Support Account", + "@exchangeSupportLoginSubtitle": { + "description": "Subtitle on support chat login screen" + }, + "exchangeSupportLoginAccessMessage": "You will only have access to the support chat feature.", + "@exchangeSupportLoginAccessMessage": { + "description": "Message explaining limited access on support-only login" + }, + "exchangeSupportLoginAccountInfo": "You will be creating an account with bullbitcoin.com that you can always access via our web app.", + "@exchangeSupportLoginAccountInfo": { + "description": "Information about account creation on support login screen" + }, "exchangeHomeDeposit": "Deposit", "@exchangeHomeDeposit": { "description": "Deposit button label" @@ -11176,11 +11192,11 @@ "@appStartupErrorTitle": { "description": "Title shown when the app fails to start up properly" }, - "appStartupErrorMessageWithBackup": "On v5.4.0 a critical bug was discovered in one of our dependencies which affect private key storage. Your app has been affected by this. You will have to delete this app and reinstall it with your backed up seed.", + "appStartupErrorMessageWithBackup": "Could not initialize. Delete and reinstall to fix.", "@appStartupErrorMessageWithBackup": { "description": "Error message shown when app startup fails due to seed storage issue and user has a backup" }, - "appStartupErrorMessageNoBackup": "On v5.4.0 a critical bug was discovered in one of our dependencies which affect private key storage. Your app has been affected by this. Contact our support team.", + "appStartupErrorMessageNoBackup": "Could not initialize. Delete and reinstall to fix. If your seed is not backed up, you can view it under Settings->Bitcoin Settings->View Seeds after reinstall.", "@appStartupErrorMessageNoBackup": { "description": "Error message shown when app startup fails due to seed storage issue and user has no backup" }, diff --git a/localization/app_es.arb b/localization/app_es.arb index 38875f8f0..293736232 100644 --- a/localization/app_es.arb +++ b/localization/app_es.arb @@ -3288,6 +3288,10 @@ "exchangeLandingFeature6": "Historial de transacciones unificado", "exchangeLandingRestriction": "El acceso a los servicios de intercambio estará restringido a países donde Bull Bitcoin pueda operar legalmente y puede requerir KYC.", "exchangeLandingLoginButton": "Iniciar sesión o registrarse", + "exchangeLandingLoginToUseSupport": "Por favor, inicie sesión o regístrese para usar el chat de soporte para problemas relacionados con el exchange.", + "exchangeSupportLoginSubtitle": "Conectar a la cuenta de soporte de Bull Bitcoin", + "exchangeSupportLoginAccessMessage": "Solo tendrá acceso a la función de chat de soporte.", + "exchangeSupportLoginAccountInfo": "Creará una cuenta con bullbitcoin.com a la que siempre podrá acceder a través de nuestra aplicación web.", "exchangeHomeDeposit": "Depositar", "exchangeHomeWithdraw": "Retirar", "exchangeKycLight": "Ligero", @@ -3758,8 +3762,8 @@ "addressViewChangeAddressesComingSoon": "Direcciones de cambio próximamente", "addressViewChangeAddressesDescription": "Mostrar direcciones de cambio de la billetera", "appStartupErrorTitle": "Error de inicio", - "appStartupErrorMessageWithBackup": "En la versión 5.4.0 se descubrió un error crítico en una de nuestras dependencias que afecta el almacenamiento de claves privadas. Su aplicación ha sido afectada por esto. Deberá eliminar esta aplicación y reinstalarla con su frase de recuperación respaldada.", - "appStartupErrorMessageNoBackup": "En la versión 5.4.0 se descubrió un error crítico en una de nuestras dependencias que afecta el almacenamiento de claves privadas. Su aplicación ha sido afectada por esto. Contacte a nuestro equipo de soporte.", + "appStartupErrorMessageWithBackup": "No se pudo inicializar. Elimine y reinstale para solucionar.", + "appStartupErrorMessageNoBackup": "No se pudo inicializar. Elimine y reinstale para solucionar. Si su frase de recuperación no está respaldada, puede verla en Configuración->Configuración de Bitcoin->Ver frases después de reinstalar.", "appStartupContactSupportButton": "Contactar Soporte", "ledgerImportTitle": "Importar Cartera Ledger", "ledgerSignTitle": "Firmar Transacción", diff --git a/localization/app_fi.arb b/localization/app_fi.arb index fce4ca65a..1a64c7663 100644 --- a/localization/app_fi.arb +++ b/localization/app_fi.arb @@ -3235,6 +3235,10 @@ "exchangeLandingFeature6": "Yhdistetty tapahtumahistoria", "exchangeLandingRestriction": "Pörssipalvelujen käyttö on rajoitettua maihin, joissa Bull Bitcoin voi toimia laillisesti, ja se voi edellyttää KYC-tunnistusta.", "exchangeLandingLoginButton": "Kirjaudu tai rekisteröidy", + "exchangeLandingLoginToUseSupport": "Ole hyvä ja kirjaudu sisään tai rekisteröidy käyttääksesi tukichattia pörssiongelmiin.", + "exchangeSupportLoginSubtitle": "Yhdistä Bull Bitcoin -tukitiliin", + "exchangeSupportLoginAccessMessage": "Sinulla on pääsy vain tukichat-ominaisuuteen.", + "exchangeSupportLoginAccountInfo": "Luot tilin osoitteeseen bullbitcoin.com, johon voit aina käyttää verkkosovelluksemme kautta.", "exchangeHomeDeposit": "Talleta", "exchangeHomeWithdraw": "Nosta", "exchangeKycLight": "Kevyt", @@ -3705,8 +3709,8 @@ "addressViewChangeAddressesComingSoon": "Vaihtoraha-osoitteet tulossa pian", "addressViewChangeAddressesDescription": "Näytä lompakon vaihtoraha-osoitteet", "appStartupErrorTitle": "Käynnistysvirhe", - "appStartupErrorMessageWithBackup": "Versiossa v5.4.0 havaittiin kriittinen virhe yhdessä riippuvuuksistamme, joka vaikuttaa yksityisten avainten tallennukseen. Tämä sovellus on kärsinyt virheestä. Sinun on poistettava tämä sovellus ja asennettava se uudelleen varmuuskopioimallasi siemenellä.", - "appStartupErrorMessageNoBackup": "Versiossa v5.4.0 havaittiin kriittinen virhe yhdessä riippuvuuksistamme, joka vaikuttaa yksityisten avainten tallennukseen. Tämä sovellus on kärsinyt virheestä. Ota yhteyttä tukitiimiimme.", + "appStartupErrorMessageWithBackup": "Alustus epäonnistui. Poista ja asenna uudelleen korjataksesi.", + "appStartupErrorMessageNoBackup": "Alustus epäonnistui. Poista ja asenna uudelleen korjataksesi. Jos siemeniäsi ei ole varmuuskopioitu, voit tarkastella sitä kohdassa Asetukset->Bitcoin-asetukset->Näytä siemenet uudelleenasennuksen jälkeen.", "appStartupContactSupportButton": "Ota yhteyttä tukeen", "ledgerImportTitle": "Tuo Ledger-lompakko", "ledgerSignTitle": "Transaktion allekirjoitus", diff --git a/localization/app_fr.arb b/localization/app_fr.arb index abbfcd319..330a4f830 100644 --- a/localization/app_fr.arb +++ b/localization/app_fr.arb @@ -3288,6 +3288,10 @@ "exchangeLandingFeature6": "Historique des transactions unifié", "exchangeLandingRestriction": "L'accès aux services d'échange sera restreint aux pays où Bull Bitcoin peut légalement opérer et peut nécessiter une vérification KYC.", "exchangeLandingLoginButton": "Se connecter ou s'inscrire", + "exchangeLandingLoginToUseSupport": "Veuillez vous connecter ou vous inscrire pour utiliser le chat de support pour les problèmes liés à l'échange.", + "exchangeSupportLoginSubtitle": "Se connecter au compte de support Bull Bitcoin", + "exchangeSupportLoginAccessMessage": "Vous aurez uniquement accès à la fonctionnalité de chat de support.", + "exchangeSupportLoginAccountInfo": "Vous allez créer un compte avec bullbitcoin.com auquel vous pourrez toujours accéder via notre application web.", "exchangeHomeDeposit": "Déposer", "exchangeHomeWithdraw": "Retirer", "exchangeKycLight": "Léger", @@ -3758,8 +3762,8 @@ "addressViewChangeAddressesComingSoon": "Adresses de change à venir", "addressViewChangeAddressesDescription": "Afficher les adresses de change du portefeuille", "appStartupErrorTitle": "Erreur de démarrage", - "appStartupErrorMessageWithBackup": "Dans la version 5.4.0, un bogue critique a été découvert dans l'une de nos dépendances qui affecte le stockage des clés privées. Votre application a été affectée par cela. Vous devrez supprimer cette application et la réinstaller avec votre phrase de récupération sauvegardée.", - "appStartupErrorMessageNoBackup": "Dans la version 5.4.0, un bogue critique a été découvert dans l'une de nos dépendances qui affecte le stockage des clés privées. Votre application a été affectée par cela. Contactez notre équipe d'assistance.", + "appStartupErrorMessageWithBackup": "Impossible d'initialiser. Supprimez et réinstallez pour corriger.", + "appStartupErrorMessageNoBackup": "Impossible d'initialiser. Supprimez et réinstallez pour corriger. Si votre phrase de récupération n'est pas sauvegardée, vous pouvez la consulter dans Paramètres->Paramètres Bitcoin->Voir les phrases après la réinstallation.", "appStartupContactSupportButton": "Contacter le support", "ledgerImportTitle": "Importer un portefeuille Ledger", "ledgerSignTitle": "Signer la transaction", diff --git a/localization/app_it.arb b/localization/app_it.arb index e9379347f..4beb6022d 100644 --- a/localization/app_it.arb +++ b/localization/app_it.arb @@ -498,7 +498,7 @@ "paySelectRecipient": "Seleziona il destinatario", "payNoActiveWallet": "Nessun portafoglio attivo", "importQrDeviceKruxStep4": "Fare clic sul pulsante \"open camera\"", - "appStartupErrorMessageWithBackup": "Su v5.4.0 è stato scoperto un bug critico in una delle nostre dipendenze che influiscono sullo storage di chiave privata. La tua app è stata influenzata da questo. Dovrai eliminare questa applicazione e reinstallarla con il tuo seme di backup.", + "appStartupErrorMessageWithBackup": "Impossibile inizializzare. Elimina e reinstalla per risolvere.", "payPasteInvoice": "Fatturato", "labelErrorUnexpected": "Errore inaspettato: {message}", "@labelErrorUnexpected": { @@ -1753,7 +1753,7 @@ "fundExchangeRegularSepaInfo": "Utilizzare solo per operazioni superiori a €20.000. Per le transazioni più piccole, utilizzare l'opzione Instant SEPA.", "fundExchangeDoneButton": "Fatto", "buyKYCLevel3": "Livello 3 - Pieno", - "appStartupErrorMessageNoBackup": "Su v5.4.0 è stato scoperto un bug critico in una delle nostre dipendenze che influiscono sullo storage di chiave privata. La tua app è stata influenzata da questo. Contatta il nostro team di supporto.", + "appStartupErrorMessageNoBackup": "Impossibile inizializzare. Elimina e reinstalla per risolvere. Se il tuo seed non è stato sottoposto a backup, puoi visualizzarlo in Impostazioni->Impostazioni Bitcoin->Visualizza semi dopo la reinstallazione.", "sellGoHome": "Vai a casa", "keystoneStep8": "Una volta che la transazione viene importata nel Keystone, rivedere l'indirizzo di destinazione e l'importo.", "psbtFlowSpecterTitle": "Istruzioni Specter", @@ -3384,6 +3384,10 @@ }, "payInvoiceDetails": "Dettagli della fattura", "exchangeLandingLoginButton": "Accedi o registrati", + "exchangeLandingLoginToUseSupport": "Effettua il login o registrati per utilizzare la chat di supporto per problemi relativi agli exchange.", + "exchangeSupportLoginSubtitle": "Connetti all'account di supporto Bull Bitcoin", + "exchangeSupportLoginAccessMessage": "Avrai accesso solo alla funzionalità di chat di supporto.", + "exchangeSupportLoginAccountInfo": "Creerai un account con bullbitcoin.com a cui potrai sempre accedere tramite la nostra app web.", "torSettingsEnableProxy": "Abilitare Tor Proxy", "bitboxScreenAddressToVerify": "Indirizzo per verificare:", "payConfirmPayment": "Conferma pagamento", diff --git a/localization/app_pt.arb b/localization/app_pt.arb index 1a964e7c7..7c558f990 100644 --- a/localization/app_pt.arb +++ b/localization/app_pt.arb @@ -496,7 +496,7 @@ "paySelectRecipient": "Selecione o destinatário", "payNoActiveWallet": "Sem carteira ativa", "importQrDeviceKruxStep4": "Clique no botão \"Câmera aberta\"", - "appStartupErrorMessageWithBackup": "Em v5.4.0 um bug crítico foi descoberto em uma de nossas dependências que afetam o armazenamento de chaves privada. Seu aplicativo foi afetado por isso. Você terá que excluir este aplicativo e reinstalá-lo com sua semente de backup.", + "appStartupErrorMessageWithBackup": "Não foi possível inicializar. Exclua e reinstale para corrigir.", "payPasteInvoice": "Fatura de pasta", "labelErrorUnexpected": "Erro inesperado: {message}", "@labelErrorUnexpected": { @@ -1750,7 +1750,7 @@ "fundExchangeRegularSepaInfo": "Use apenas para transações acima de € 20.000. Para transações menores, use a opção Instant SEPA.", "fundExchangeDoneButton": "Feito", "buyKYCLevel3": "Nível 3 - Total", - "appStartupErrorMessageNoBackup": "Em v5.4.0 um bug crítico foi descoberto em uma de nossas dependências que afetam o armazenamento de chaves privada. Seu aplicativo foi afetado por isso. Contacte a nossa equipa de apoio.", + "appStartupErrorMessageNoBackup": "Não foi possível inicializar. Exclua e reinstale para corrigir. Se sua frase de recuperação não tiver backup, você pode visualizá-la em Configurações->Configurações de Bitcoin->Ver frases após a reinstalação.", "sellGoHome": "Vai para casa", "keystoneStep8": "Uma vez que a transação é importada em seu Keystone, revise o endereço de destino e o valor.", "psbtFlowSpecterTitle": "Instruções de espectro", @@ -3359,6 +3359,10 @@ }, "payInvoiceDetails": "Detalhes da fatura", "exchangeLandingLoginButton": "Login Ou Inscreva-se", + "exchangeLandingLoginToUseSupport": "Por favor, faça login ou inscreva-se para usar o chat de suporte para questões relacionadas à exchange.", + "exchangeSupportLoginSubtitle": "Conectar à conta de suporte Bull Bitcoin", + "exchangeSupportLoginAccessMessage": "Você terá acesso apenas ao recurso de chat de suporte.", + "exchangeSupportLoginAccountInfo": "Você estará criando uma conta com bullbitcoin.com que poderá sempre acessar através do nosso aplicativo web.", "torSettingsEnableProxy": "Ativar Proxy Tor", "bitboxScreenAddressToVerify": "Endereço para verificar:", "payConfirmPayment": "Confirmar pagamento", diff --git a/localization/app_ru.arb b/localization/app_ru.arb index 779a121b4..f7fe7ed17 100644 --- a/localization/app_ru.arb +++ b/localization/app_ru.arb @@ -496,7 +496,7 @@ "paySelectRecipient": "Выберите получателя", "payNoActiveWallet": "Нет активного кошелька", "importQrDeviceKruxStep4": "Нажмите кнопку «открытая камера»", - "appStartupErrorMessageWithBackup": "На v5.4.0 был обнаружен критический жучок в одной из наших зависимостей, которые влияют на личное хранилище ключей. Это повлияло на ваше приложение. Вам придется удалить это приложение и переустановить его с резервным семенем.", + "appStartupErrorMessageWithBackup": "Не удалось инициализировать. Удалите и переустановите, чтобы исправить.", "payPasteInvoice": "Счет-фактура", "labelErrorUnexpected": "Неожиданная ошибка: {message}", "@labelErrorUnexpected": { @@ -1750,7 +1750,7 @@ "fundExchangeRegularSepaInfo": "Использовать только для транзакций выше €20 000. Для небольших транзакций используйте опцию Instant SEPA.", "fundExchangeDoneButton": "Дон", "buyKYCLevel3": "Уровень 3 - полный", - "appStartupErrorMessageNoBackup": "На v5.4.0 был обнаружен критический жучок в одной из наших зависимостей, которые влияют на личное хранилище ключей. Это повлияло на ваше приложение. Свяжитесь с нашей группой поддержки.", + "appStartupErrorMessageNoBackup": "Не удалось инициализировать. Удалите и переустановите, чтобы исправить. Если у вашей фразы восстановления нет резервной копии, вы можете просмотреть ее в Настройки->Настройки Bitcoin->Просмотр фраз после переустановки.", "sellGoHome": "Иди домой", "keystoneStep8": "После того, как транзакция импортируется в ваш Keystone, проверьте адрес назначения и сумму.", "psbtFlowSpecterTitle": "Инструкции по спектру", @@ -3381,6 +3381,10 @@ }, "payInvoiceDetails": "Детали счетов-фактур", "exchangeLandingLoginButton": "Зарегистрироваться или зарегистрироваться", + "exchangeLandingLoginToUseSupport": "Пожалуйста, войдите или зарегистрируйтесь, чтобы использовать чат поддержки для вопросов, связанных с биржей.", + "exchangeSupportLoginSubtitle": "Подключиться к учетной записи поддержки Bull Bitcoin", + "exchangeSupportLoginAccessMessage": "У вас будет доступ только к функции чата поддержки.", + "exchangeSupportLoginAccountInfo": "Вы создадите учетную запись на bullbitcoin.com, к которой всегда сможете получить доступ через наше веб-приложение.", "torSettingsEnableProxy": "Включить Tor Proxy", "bitboxScreenAddressToVerify": "Адрес для проверки:", "payConfirmPayment": "Подтвердить оплату", diff --git a/localization/app_uk.arb b/localization/app_uk.arb index cd65a2b34..088382898 100644 --- a/localization/app_uk.arb +++ b/localization/app_uk.arb @@ -1484,7 +1484,7 @@ "passportStep12": "Біткойн-гаманець Bull попросить вас сканування QR-коду на Паспорті. Сканування.", "payNoActiveWallet": "Немає активного гаманця", "importQrDeviceKruxStep4": "Натисніть кнопку \"відкрита камера\"", - "appStartupErrorMessageWithBackup": "На v5.4.0 критична помилка була виявлена в одному з наших залежностей, які впливають на зберігання приватного ключа. Ваш додаток був уражений цим. Ви повинні видалити цей додаток і перевстановити його з заднім насінням.", + "appStartupErrorMessageWithBackup": "Не вдалося ініціалізувати. Видаліть і перевстановіть, щоб виправити.", "payPasteInvoice": "Паста Invoice", "labelErrorUnexpected": "Несподівана помилка: {message}", "@labelErrorUnexpected": { @@ -2350,7 +2350,7 @@ "payReviewPayment": "Огляд платежів", "electrumBitcoinSslInfo": "Якщо не вказано протокол, ssl буде використовуватися за замовчуванням.", "buyKYCLevel3": "Рівень 3 - Повний", - "appStartupErrorMessageNoBackup": "На v5.4.0 критична помилка була виявлена в одному з наших залежностей, які впливають на зберігання приватного ключа. Ваш додаток був уражений цим. Зв'язатися з нашою командою підтримки.", + "appStartupErrorMessageNoBackup": "Не вдалося ініціалізувати. Видаліть і перевстановіть, щоб виправити. Якщо ваша фраза відновлення не має резервної копії, ви можете переглянути її в Налаштування->Налаштування Bitcoin->Переглянути фрази після перевстановлення.", "keystoneStep8": "Після того, як угода була імпортована у Keystone, перевірте адресу призначення та суму.", "psbtFlowSpecterTitle": "Інструкція Specter", "importMnemonicChecking": "Перевірити...", @@ -3561,6 +3561,10 @@ }, "payInvoiceDetails": "Деталі вступу", "exchangeLandingLoginButton": "Увійти", + "exchangeLandingLoginToUseSupport": "Будь ласка, увійдіть або зареєструйтесь, щоб використовувати чат підтримки для питань, пов'язаних з біржею.", + "exchangeSupportLoginSubtitle": "Підключитися до облікового запису підтримки Bull Bitcoin", + "exchangeSupportLoginAccessMessage": "У вас буде доступ лише до функції чату підтримки.", + "exchangeSupportLoginAccountInfo": "Ви створите обліковий запис на bullbitcoin.com, до якого завжди зможете отримати доступ через наш веб-додаток.", "torSettingsEnableProxy": "Увімкнути Tor Proxy", "bitboxScreenAddressToVerify": "Адреса для перевірки:", "bitboxErrorPermissionDenied": "Для підключення до пристроїв BitBox потрібні дозволи на USB.", diff --git a/localization/app_zh.arb b/localization/app_zh.arb index b2aa4828a..224dc39da 100644 --- a/localization/app_zh.arb +++ b/localization/app_zh.arb @@ -3384,6 +3384,9 @@ }, "payInvoiceDetails": "发票细节", "exchangeLandingLoginButton": "标志", + "exchangeSupportLoginSubtitle": "连接到 Bull Bitcoin 支持账户", + "exchangeSupportLoginAccessMessage": "您将只能访问支持聊天功能。", + "exchangeSupportLoginAccountInfo": "您将在 bullbitcoin.com 创建一个账户,您可以随时通过我们的网络应用访问。", "torSettingsEnableProxy": "Enable Tor Proxy", "bitboxScreenAddressToVerify": "地址:", "payConfirmPayment": "普通工资",