Skip to content
Original file line number Diff line number Diff line change
@@ -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<SupportChatMessageAttachment> execute() async {
try {
List<String> 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);
}
5 changes: 5 additions & 0 deletions lib/core/exchange/exchange_locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -462,6 +463,10 @@ class ExchangeLocator {
),
);

locator.registerFactory<CreateLogAttachmentUsecase>(
() => CreateLogAttachmentUsecase(),
);

locator.registerFactory<LabelExchangeOrdersUsecase>(
() => LabelExchangeOrdersUsecase(
labelDatasource: locator<LabelDatasource>(),
Expand Down
4 changes: 2 additions & 2 deletions lib/features/buy/ui/screens/buy_confirm_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -142,7 +142,7 @@ class BuyConfirmScreen extends StatelessWidget {
context.read<BuyBloc>().add(const BuyEvent.confirmOrder());
},
bgColor: context.appColors.secondary,
textColor: context.appColors.onPrimary,
textColor: context.appColors.onSecondary,
),
],
),
Expand Down
8 changes: 5 additions & 3 deletions lib/features/buy/ui/widgets/buy_amount_input_fields.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class _BuyAmountInputFieldsState extends State<BuyAmountInputFields> {
mainAxisSize: .min,
mainAxisAlignment: .spaceBetween,
children: [
Expanded(
Expanded(
child: TextFormField(
controller: _amountController,
keyboardType: const TextInputType.numberWithOptions(
Expand All @@ -109,7 +109,7 @@ class _BuyAmountInputFieldsState extends State<BuyAmountInputFields> {
decimalDigits: amountInputDecimals,
).format(0),
hintStyle: context.font.displaySmall?.copyWith(
color: context.appColors.primary,
color: context.appColors.onSurfaceVariant,
),
border: InputBorder.none,
),
Expand Down Expand Up @@ -229,7 +229,9 @@ class _BuyAmountInputFieldsState extends State<BuyAmountInputFields> {
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,
),
),
),
)
Expand Down
4 changes: 2 additions & 2 deletions lib/features/buy/ui/widgets/buy_confirm_detail_row.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class BuyConfirmDetailRow extends StatelessWidget {
Text(
label,
style: theme.textTheme.bodyMedium?.copyWith(
color: context.appColors.surfaceContainer,
color: context.appColors.onSurfaceVariant,
),
),

Expand All @@ -32,7 +32,7 @@ class BuyConfirmDetailRow extends StatelessWidget {
value!,
textAlign: .end,
style: theme.textTheme.bodyMedium?.copyWith(
color: context.appColors.outlineVariant,
color: context.appColors.secondary,
),
),
),
Expand Down
21 changes: 14 additions & 7 deletions lib/features/buy/ui/widgets/buy_destination_input_fields.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,20 @@ class _BuyDestinationInputFieldsState extends State<BuyDestinationInputFields> {
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,
),
),
),
],
Expand Down Expand Up @@ -117,17 +122,19 @@ class _BuyDestinationInputFieldsState extends State<BuyDestinationInputFields> {
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(
Expand Down
24 changes: 21 additions & 3 deletions lib/features/exchange/ui/exchange_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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');

Expand Down Expand Up @@ -74,16 +76,32 @@ 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<SettingsCubit>().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,
pageBuilder: (context, state) {
return NoTransitionPage(
key: state.pageKey,
child: BlocListener<ExchangeCubit, ExchangeState>(
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);
Expand Down
46 changes: 27 additions & 19 deletions lib/features/exchange/ui/screens/exchange_home_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -87,10 +88,6 @@ class ExchangeHomeScreen extends StatelessWidget {
BlocBuilder<PriceChartCubit, PriceChartState>(
builder: (context, priceChartState) {
final showChart = priceChartState.showChart;
final hasApiKey = context.select(
(ExchangeCubit cubit) =>
cubit.state.apiKeyException == null,
);

return SliverAppBar(
backgroundColor: Colors.transparent,
Expand All @@ -113,7 +110,7 @@ class ExchangeHomeScreen extends StatelessWidget {
},
)
: SizedBox(
width: hasApiKey ? 96 : 48,
width: 96,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expand All @@ -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<ExchangeCubit>()
.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,
Expand Down
Loading