diff --git a/lib/design/background/hypha_half_background.dart b/lib/design/background/hypha_half_background.dart index c28d0b28..94e97350 100644 --- a/lib/design/background/hypha_half_background.dart +++ b/lib/design/background/hypha_half_background.dart @@ -5,15 +5,16 @@ class HyphaHalfBackground extends StatelessWidget { final Color? backgroundColor; final Widget? child; final bool showTopBar; + final double? height; - const HyphaHalfBackground({super.key, this.backgroundColor, this.child, required this.showTopBar}); + const HyphaHalfBackground({super.key, this.backgroundColor, this.child, required this.showTopBar, this.height}); @override Widget build(BuildContext context) { return Stack( children: [ Container( - height: 170, + height: height ?? 170, width: double.infinity, decoration: BoxDecoration( color: backgroundColor, diff --git a/lib/ui/send/components/send_memo_field.dart b/lib/ui/send/components/send_memo_field.dart new file mode 100644 index 00000000..1ebe704e --- /dev/null +++ b/lib/ui/send/components/send_memo_field.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:get/get.dart'; +import 'package:hypha_wallet/design/hypha_card.dart'; +import 'package:hypha_wallet/design/hypha_colors.dart'; +import 'package:hypha_wallet/design/themes/extensions/theme_extension_provider.dart'; +import 'package:hypha_wallet/ui/send/interactor/send_bloc.dart'; +import 'package:hypha_wallet/ui/shared/components/text_request_bottom_sheet.dart'; +import 'package:hypha_wallet/ui/shared/ui_constants.dart'; + +class SendMemoField extends StatelessWidget { + const SendMemoField({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + buildWhen: (previous, current) => previous.memo != current.memo, + builder: (context, state) { + return GestureDetector( + onTap: () { + showModalBottomSheet( + isScrollControlled: true, + clipBehavior: Clip.hardEdge, + context: context, + builder: (modelContext) => FractionallySizedBox( + heightFactor: UIConstants.bottomSheetHeightFraction, + child: TextRequestBottomSheet( + title: 'Enter Memo', + initialText: state.memo ?? '', + onPressed: (String? text) { + context.read().add(SendEvent.onMemoEntered(text)); + Get.back(); + }), + ), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(30)), + ), + ); + }, + child: HyphaCard( + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Expanded( + child: Text( + state.memo ?? 'Memo (optional)', + style: context.hyphaTextTheme.regular + .copyWith(color: state.memo == null ? HyphaColors.midGrey : null), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + state.memo == null ? const SizedBox.shrink() : const Icon(Icons.edit) + ], + ), + ), + ), + ); + }, + ); + } +} \ No newline at end of file diff --git a/lib/ui/send/components/send_review_bottom_sheet.dart b/lib/ui/send/components/send_review_bottom_sheet.dart new file mode 100644 index 00000000..bd778772 --- /dev/null +++ b/lib/ui/send/components/send_review_bottom_sheet.dart @@ -0,0 +1,123 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:hypha_wallet/design/avatar_image/hypha_avatar_image.dart'; +import 'package:hypha_wallet/design/background/hypha_half_background.dart'; +import 'package:hypha_wallet/design/background/hypha_page_background.dart'; +import 'package:hypha_wallet/design/buttons/button_type.dart'; +import 'package:hypha_wallet/design/buttons/hypha_app_button.dart'; +import 'package:hypha_wallet/design/hypha_card.dart'; +import 'package:hypha_wallet/design/hypha_colors.dart'; +import 'package:hypha_wallet/design/themes/extensions/theme_extension_provider.dart'; +import 'package:hypha_wallet/ui/send/components/send_to_user_row.dart'; +import 'package:hypha_wallet/ui/send/interactor/send_bloc.dart'; + +class SendReviewBottomSheet extends StatelessWidget { + const SendReviewBottomSheet({super.key}); + + @override + Widget build(BuildContext context) { + return HyphaPageBackground( + withGradient: true, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + children: [ + const HyphaHalfBackground(showTopBar: true, height: 120), + Padding( + padding: const EdgeInsets.only(top: 60, left: 24, right: 24, bottom: 24), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BlocBuilder( + builder: (context, state) { + return HyphaAvatarImage( + imageRadius: 50, + imageFromUrl: state.tokenData.image, + name: state.tokenData.name, + ); + }, + ), + const SizedBox(height: 12), + BlocBuilder( + builder: (context, state) { + return Text( + state.formattedAmount, + style: context.hyphaTextTheme.popsExtraLargeAndLight, + ); + }, + ), + BlocBuilder( + builder: (context, state) { + return Text( + state.tokenData.name, + style: context.hyphaTextTheme.ralMediumBody.copyWith(height: 0), + ); + }, + ), + const SizedBox(height: 24), + const SendToUserRow(imageRadius: 30), + const SizedBox(height: 16), + BlocBuilder( + builder: (context, state) { + return state.memo == null + ? const SizedBox.shrink() + : HyphaCard( + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Expanded( + child: Text( + state.memo ?? 'Memo (optional)', + style: context.hyphaTextTheme.regular + .copyWith(color: state.memo == null ? HyphaColors.midGrey : null), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ) + ], + ), + ), + ); + }, + ), + const SizedBox(height: 16), + HyphaCard( + child: Padding( + padding: const EdgeInsets.all(16), + child: Row( + children: [ + Expanded( + child: Text( + 'Always free and instant!', + style: context.hyphaTextTheme.regular.copyWith(color: HyphaColors.midGrey), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ) + ], + ), + ), + ), + const SizedBox(height: 100), + HyphaAppButton( + title: 'Edit', + buttonType: ButtonType.secondary, + onPressed: () {}, + ), + const SizedBox(height: 16), + HyphaAppButton( + title: 'Send', + onPressed: () {}, + ), + ], + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/ui/send/components/send_to_user_row.dart b/lib/ui/send/components/send_to_user_row.dart new file mode 100644 index 00000000..7e701d11 --- /dev/null +++ b/lib/ui/send/components/send_to_user_row.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:hypha_wallet/design/avatar_image/hypha_avatar_image.dart'; +import 'package:hypha_wallet/design/hypha_card.dart'; +import 'package:hypha_wallet/design/themes/extensions/theme_extension_provider.dart'; +import 'package:hypha_wallet/ui/send/interactor/send_bloc.dart'; + +class SendToUserRow extends StatelessWidget { + final double imageRadius; + + const SendToUserRow({super.key, required this.imageRadius}); + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + return ListTile( + contentPadding: EdgeInsets.zero, + leading: HyphaAvatarImage( + imageRadius: imageRadius, + name: state.receiverUser.userName, + imageFromUrl: state.receiverUser.userImage, + ), + title: Text( + state.receiverUser.userName ?? state.receiverUser.accountName, + style: context.hyphaTextTheme.smallTitles, + ), + subtitle: Text('@${state.receiverUser.accountName}', style: context.hyphaTextTheme.ralMediumBody), + trailing: HyphaCard( + borderRadius: BorderRadius.circular(10), + child: const Padding( + padding: EdgeInsets.all(12), + child: Text('To'), + ), + ), + ); + }, + ); + } +} diff --git a/lib/ui/send/components/send_view.dart b/lib/ui/send/components/send_view.dart index 47d96bee..ed5f275a 100644 --- a/lib/ui/send/components/send_view.dart +++ b/lib/ui/send/components/send_view.dart @@ -10,6 +10,9 @@ import 'package:hypha_wallet/design/buttons/hypha_app_button.dart'; import 'package:hypha_wallet/design/hypha_card.dart'; import 'package:hypha_wallet/design/hypha_colors.dart'; import 'package:hypha_wallet/design/themes/extensions/theme_extension_provider.dart'; +import 'package:hypha_wallet/ui/send/components/send_memo_field.dart'; +import 'package:hypha_wallet/ui/send/components/send_review_bottom_sheet.dart'; +import 'package:hypha_wallet/ui/send/components/send_to_user_row.dart'; import 'package:hypha_wallet/ui/send/data/amount_percentage.dart'; import 'package:hypha_wallet/ui/send/data/keypad_key.dart'; import 'package:hypha_wallet/ui/send/interactor/send_bloc.dart'; @@ -33,7 +36,21 @@ class SendView extends StatelessWidget { builder: (context, state) { return HyphaSafeBottomNavigationBar( child: HyphaAppButton( - onPressed: () {}, + onPressed: () { + // GERE + showModalBottomSheet( + isScrollControlled: true, + clipBehavior: Clip.hardEdge, + context: context, + builder: (childContext) => BlocProvider.value( + value: BlocProvider.of(context), + child: const SendReviewBottomSheet(), + ), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(30)), + ), + ); + }, title: 'Send', buttonType: ButtonType.primary, isActive: state.isSubmitEnabled, @@ -56,9 +73,9 @@ class SendView extends StatelessWidget { }, ), const _AvailableBalanceWidget(), - const _ToUserRow(), + const SendToUserRow(imageRadius: 20), const SizedBox(height: 24), - const _MemoField(), + const SendMemoField(), const SizedBox(height: 24), const _PercentagesWidget(), const SizedBox(height: 24), @@ -146,89 +163,6 @@ class _PercentagesWidget extends StatelessWidget { } } -class _MemoField extends StatelessWidget { - const _MemoField(); - - @override - Widget build(BuildContext context) { - return BlocBuilder( - buildWhen: (previous, current) => previous.memo != current.memo, - builder: (context, state) { - return GestureDetector( - onTap: () { - showModalBottomSheet( - isScrollControlled: true, - clipBehavior: Clip.hardEdge, - context: context, - builder: (modelContext) => FractionallySizedBox( - heightFactor: UIConstants.bottomSheetHeightFraction, - child: TextRequestBottomSheet( - title: 'Enter Memo', - initialText: state.memo ?? '', - onPressed: (String? text) { - context.read().add(SendEvent.onMemoEntered(text)); - Get.back(); - }), - ), - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.vertical(top: Radius.circular(30)), - ), - ); - }, - child: HyphaCard( - child: Padding( - padding: const EdgeInsets.all(16), - child: Row( - children: [ - Expanded( - child: Text( - state.memo ?? 'Memo (optional)', - style: context.hyphaTextTheme.regular - .copyWith(color: state.memo == null ? HyphaColors.midGrey : null), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - state.memo == null ? const SizedBox.shrink() : const Icon(Icons.edit) - ], - ), - ), - ), - ); - }, - ); - } -} - -class _ToUserRow extends StatelessWidget { - const _ToUserRow(); - - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) { - return ListTile( - contentPadding: EdgeInsets.zero, - leading: HyphaAvatarImage( - imageRadius: 20, - name: state.receiverUser.userName, - imageFromUrl: state.receiverUser.userImage, - ), - title: Text(state.receiverUser.userName ?? state.receiverUser.accountName), - subtitle: Text(state.receiverUser.accountName), - trailing: HyphaCard( - borderRadius: BorderRadius.circular(10), - child: const Padding( - padding: EdgeInsets.all(12), - child: Text('To'), - ), - ), - ); - }, - ); - } -} - class _AvailableBalanceWidget extends StatelessWidget { const _AvailableBalanceWidget(); diff --git a/lib/ui/send/interactor/send_bloc.dart b/lib/ui/send/interactor/send_bloc.dart index 24a635bc..23f0b51f 100644 --- a/lib/ui/send/interactor/send_bloc.dart +++ b/lib/ui/send/interactor/send_bloc.dart @@ -4,6 +4,7 @@ import 'package:bloc/bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hypha_wallet/core/network/models/user_profile_data.dart'; import 'package:hypha_wallet/ui/architecture/interactor/page_states.dart'; +import 'package:hypha_wallet/core/extension/scope_functions.dart'; import 'package:hypha_wallet/ui/send/data/amount_percentage.dart'; import 'package:hypha_wallet/ui/send/data/keypad_key.dart'; import 'package:hypha_wallet/ui/wallet/data/wallet_token_data.dart'; diff --git a/lib/ui/send/interactor/send_state.dart b/lib/ui/send/interactor/send_state.dart index a44379fb..30926760 100644 --- a/lib/ui/send/interactor/send_state.dart +++ b/lib/ui/send/interactor/send_state.dart @@ -17,4 +17,8 @@ class SendState with _$SendState { final parsedAmount = double.tryParse(userEnteredAmount ?? '0') ?? 0; return parsedAmount > 0 && parsedAmount <= (tokenData.userOwnedAmount ?? 0); } + + String get formattedAmount { + return userEnteredAmount?.let((it) => double.tryParse(it)?.toStringAsFixed(tokenData.precision) ?? it) ?? '0'; + } } diff --git a/lib/ui/send/send_page.dart b/lib/ui/send/send_page.dart index 90de1ac6..38aeb814 100644 --- a/lib/ui/send/send_page.dart +++ b/lib/ui/send/send_page.dart @@ -15,10 +15,10 @@ class SendPage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => GetIt.I.get(param1: receiverUser, param2: tokenData) - ..add( - const SendEvent.initial(), - ), + create: (context) => GetIt.I.get( + param1: receiverUser, + param2: tokenData, + )..add(const SendEvent.initial()), child: BlocListener( listenWhen: (previous, current) => previous.command != current.command, listener: (context, state) {