diff --git a/wallet/assets/images/svg/bottom_right_curved_grey_bg.svg b/wallet/assets/images/svg/bottom_right_curved_grey_bg.svg new file mode 100644 index 0000000000..b8a647552f --- /dev/null +++ b/wallet/assets/images/svg/bottom_right_curved_grey_bg.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/wallet/assets/images/svg/curved_corner_red_bg.svg b/wallet/assets/images/svg/curved_corner_red_bg.svg new file mode 100644 index 0000000000..86d0b6040a --- /dev/null +++ b/wallet/assets/images/svg/curved_corner_red_bg.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/wallet/i18n/de.json b/wallet/i18n/de.json index 722b102922..5d706c133a 100644 --- a/wallet/i18n/de.json +++ b/wallet/i18n/de.json @@ -361,7 +361,9 @@ "bought_nft": "Gekauft", "resolution": "Auflösung", "set_lockscreen": "Instellen als vergrendelscherm", + "ipfs_cid": "IPFS-CID", + "available": "verfügbar", + "ea": "ea", "maintenance_mode_message": "We ondervinden technische problemen en hebben tijdelijk de onderhoudsmodus gestart voor het oplossen van problemen. Maak je geen zorgen, je collectie is veilig. U kunt echter geen on-chain-transacties starten totdat we het probleem hebben opgelost en de normale functionaliteit hebben hersteld.", "maintenance_mode_header": "onderhoudsstand" - } diff --git a/wallet/i18n/en.json b/wallet/i18n/en.json index e4414d045d..aed9c0ea3a 100644 --- a/wallet/i18n/en.json +++ b/wallet/i18n/en.json @@ -363,7 +363,9 @@ "checkout": "Checkout", "artist": "Artist", "set_lockscreen": "Set as lockscreen", + "ipfs_cid": "IPFS CID", + "available": "available", + "ea": "ea", "maintenance_mode_message": "We are experiencing technical issues and have temporarily initiated maintenance mode for troubleshooting. Don't worry, your collection is safe. However, you cannot initiate on-chain transactions until we've resolved the problem and restored normal functionality.", "maintenance_mode_header": "Maintenance Mode" - } diff --git a/wallet/i18n/es.json b/wallet/i18n/es.json index 8230c9a91a..4a1645cb40 100644 --- a/wallet/i18n/es.json +++ b/wallet/i18n/es.json @@ -361,7 +361,9 @@ "resolution": "resolución", "bought_nft": "Comprado", "set_lockscreen": "Establecer como pantalla de bloqueo", + "ipfs_cid": "CID IPFS", + "available": "disponible", + "ea": "cada uno", "maintenance_mode_message": "Estamos experimentando problemas técnicos y hemos iniciado temporalmente el modo de mantenimiento para solucionar problemas. No te preocupes, tu colección está segura. Sin embargo, no puede iniciar transacciones en cadena hasta que hayamos resuelto el problema y restablecido la funcionalidad normal.", "maintenance_mode_header": "Modo de mantenimiento" - } \ No newline at end of file diff --git a/wallet/i18n/id.json b/wallet/i18n/id.json index 0ef5f70bb9..d2a55db52e 100644 --- a/wallet/i18n/id.json +++ b/wallet/i18n/id.json @@ -361,7 +361,9 @@ "bought_nft": "Dibeli", "resolution": "resolusi", "set_lockscreen": "Tetapkan sebagai layar kunci", + "ipfs_cid": "ID Pelanggan IPFS", + "available": "tersedia", + "ea": "ea", "maintenance_mode_message": "Kami mengalami masalah teknis dan untuk sementara memulai mode pemeliharaan untuk pemecahan masalah. Jangan khawatir, koleksi Anda aman. Namun, Anda tidak dapat memulai transaksi on-chain sampai kami menyelesaikan masalah dan memulihkan fungsionalitas normal.", "maintenance_mode_header": "Mode Pemeliharaan" - } \ No newline at end of file diff --git a/wallet/i18n/ja.json b/wallet/i18n/ja.json index dfbb5ccde9..ef669043bb 100644 --- a/wallet/i18n/ja.json +++ b/wallet/i18n/ja.json @@ -361,7 +361,9 @@ "resolution": "解像度", "bought_nft": "買った", "set_lockscreen": "ロック画面に設定", + "ipfs_cid": "IPFS CID", + "available": "利用可能", + "ea": "えー", "maintenance_mode_message": "技術的な問題が発生しており、トラブルシューティングのために一時的にメンテナンス モードを開始しました。心配はいりません。あなたのコレクションは安全です。ただし、問題が解決され、通常の機能が回復するまで、オンチェーン トランザクションを開始することはできません。", "maintenance_mode_header": "メンテナンスモード" - } \ No newline at end of file diff --git a/wallet/i18n/ko.json b/wallet/i18n/ko.json index 45d4426411..66141dab19 100644 --- a/wallet/i18n/ko.json +++ b/wallet/i18n/ko.json @@ -360,7 +360,9 @@ "resolution": "해결", "bought_nft": "구입했다", "set_lockscreen": "잠금 화면으로 설정", + "ipfs_cid": "IPFS CID", + "available": "사용 가능", + "ea": "에아", "maintenance_mode_message": "기술적인 문제가 발생했으며 문제 해결을 위해 일시적으로 유지 관리 모드를 시작했습니다. 걱정하지 마세요. 컬렉션은 안전합니다. 그러나 문제를 해결하고 정상적인 기능을 복원할 때까지 온체인 트랜잭션을 시작할 수 없습니다.", "maintenance_mode_header": "유지 관리 모드" - } \ No newline at end of file diff --git a/wallet/i18n/ru.json b/wallet/i18n/ru.json index d0904e2900..68e8c71d8e 100644 --- a/wallet/i18n/ru.json +++ b/wallet/i18n/ru.json @@ -361,7 +361,9 @@ "bought_nft": "Купленный", "resolution": "разрешающая способность", "set_lockscreen": "Установить как экран блокировки", + "ipfs_cid": "CID ИПФС", + "available": "доступный", + "ea": "шт.", "maintenance_mode_message": "У нас возникли технические проблемы, и мы временно запустили режим обслуживания для устранения неполадок. Не волнуйтесь, ваша коллекция в безопасности. Однако вы не можете инициировать транзакции в сети, пока мы не решим проблему и не восстановим нормальную работу.", "maintenance_mode_header": "Режим технического обслуживания" - } \ No newline at end of file diff --git a/wallet/i18n/vi.json b/wallet/i18n/vi.json index 371ec95f66..54b32b4816 100644 --- a/wallet/i18n/vi.json +++ b/wallet/i18n/vi.json @@ -126,7 +126,7 @@ "mnemonic_is_empty": "Mnemonic là trống", "user_name_doesnt_exists": "Tên người dùng không tồn tại", "user_name_invalid": "Tên người dùng không hợp lệ", - "invalid_input": "đâu vao không hợp lệ", + "invalid_input": "đâu vao không hợp lệ", "purchase_nft_success": "Đã mua thành công NFT này.", "payout_request_success": "Yêu cầu thanh toán thành công. %S", "trade_create_success": "Giao dịch trên NFT này đã được tạo thành công.", @@ -349,7 +349,7 @@ "enter_description_text": "Nhập mô tả", "enter_subject_text": "Nhập chủ đề", "free": "Tự do", - "thank_you_for_feedback": "Cảm ơn phản hôi của bạn.", + "thank_you_for_feedback": "Cảm ơn phản hôi của bạn.", "claim_free_nft": "Yêu cầu NFT miễn phí của bạn", "before_too_late": "Trước khi quá muộn!", "please_try_again_later": "Vui lòng thử lại sau", @@ -361,7 +361,9 @@ "resolution": "nghị quyết", "bought_nft": "Đã mua", "set_lockscreen": "Đặt làm màn hình khóa", + "ipfs_cid": "IPFS CID", + "available": "có sẵn", + "ea": "ea", "maintenance_mode_message": "Chúng tôi đang gặp sự cố kỹ thuật và đã tạm thời bắt đầu chế độ bảo trì để khắc phục sự cố. Đừng lo lắng, bộ sưu tập của bạn vẫn an toàn. Tuy nhiên, bạn không thể bắt đầu các giao dịch trên chuỗi cho đến khi chúng tôi giải quyết xong sự cố và khôi phục chức năng bình thường.", "maintenance_mode_header": "Chế độ bảo trì" - } \ No newline at end of file diff --git a/wallet/lib/generated/locale_keys.g.dart b/wallet/lib/generated/locale_keys.g.dart index 5d444f9935..a68efcdc46 100644 --- a/wallet/lib/generated/locale_keys.g.dart +++ b/wallet/lib/generated/locale_keys.g.dart @@ -363,6 +363,9 @@ abstract class LocaleKeys { static const resolution = 'resolution'; static const bought_nft = 'bought_nft'; static const set_lockscreen = 'set_lockscreen'; + static const ipfs_cid = 'ipfs_cid'; + static const available = 'available'; + static const ea = 'ea'; static const maintenance_mode_message = 'maintenance_mode_message'; static const maintenance_mode_header = 'maintenance_mode_header'; diff --git a/wallet/lib/model/nft_ownership_history.dart b/wallet/lib/model/nft_ownership_history.dart index 61de807741..2a9fd11be8 100644 --- a/wallet/lib/model/nft_ownership_history.dart +++ b/wallet/lib/model/nft_ownership_history.dart @@ -4,11 +4,11 @@ class NftOwnershipHistory { final String itemID; final String cookbookID; final String senderName; - final String receiver; + final String receiverID; final int createdAt; NftOwnershipHistory( - {required this.itemID, required this.cookbookID, required this.senderName, required this.receiver, required this.createdAt}); + {required this.itemID, required this.cookbookID, required this.senderName, required this.receiverID, required this.createdAt}); factory NftOwnershipHistory.fromJson(Map json) { final itemID = json[kItemId] as String; @@ -17,7 +17,22 @@ class NftOwnershipHistory { final receiver = json[kTo] as String; final createdAt = int.parse(json[kCreatedAt] as String); return NftOwnershipHistory( - receiver: receiver, + receiverID: receiver, + cookbookID: cookbookID, + senderName: senderName, + itemID: itemID, + createdAt: createdAt, + ); + } + + factory NftOwnershipHistory.fromCookBookAndRecipeJson(Map json) { + final itemID = json[kItemIdKey] as String; + final cookbookID = json[kCookbookId] as String; + final senderName = json[kSenderName] as String; + final receiver = json[kReceiver] as String; + final createdAt = int.parse(json[kCreatedAt] as String); + return NftOwnershipHistory( + receiverID: receiver, cookbookID: cookbookID, senderName: senderName, itemID: itemID, diff --git a/wallet/lib/pages/detailed_asset_view/widgets/tab_fields.dart b/wallet/lib/pages/detailed_asset_view/widgets/tab_fields.dart index 50f7faa317..09f1e787f9 100644 --- a/wallet/lib/pages/detailed_asset_view/widgets/tab_fields.dart +++ b/wallet/lib/pages/detailed_asset_view/widgets/tab_fields.dart @@ -8,7 +8,6 @@ import 'package:pylons_wallet/model/nft.dart'; import 'package:pylons_wallet/model/nft_ownership_history.dart'; import 'package:pylons_wallet/utils/constants.dart'; import 'package:pylons_wallet/utils/enums.dart'; -import 'package:pylons_wallet/utils/extension.dart'; import '../../../generated/locale_keys.g.dart'; @@ -46,16 +45,13 @@ class _TabFieldState extends State { switch (widget.nft.type) { case NftType.TYPE_RECIPE: return { - LocaleKeys.owned_by.tr(): widget.owner, - LocaleKeys.edition.tr(): '#${widget.nft.amountMinted} of ${widget.nft.quantity}', + LocaleKeys.owner.tr(): widget.owner, + "${LocaleKeys.edition.tr()}#": '#${widget.nft.amountMinted} of ${widget.nft.quantity}', LocaleKeys.royalty_text.tr(): widget.nft.tradePercentage, - LocaleKeys.creation.tr(): widget.nft.createdAt, }; case NftType.TYPE_ITEM: return { - LocaleKeys.owned_by.tr(): widget.owner, - LocaleKeys.size.tr(): widget.nft.getAssetSize(), - LocaleKeys.creation.tr(): widget.nft.createdAt, + LocaleKeys.owner.tr(): widget.owner, }; case NftType.TYPE_TRADE: return {}; @@ -65,14 +61,23 @@ class _TabFieldState extends State { Map getNFTDetailsMap() { switch (widget.nft.type) { case NftType.TYPE_RECIPE: - return {LocaleKeys.recipe_id.tr(): widget.nft.recipeID, LocaleKeys.resolution.tr(): widget.nft.getAssetSize(), kIpfsCid: widget.nft.cid}; + return { + LocaleKeys.recipe_id.tr(): widget.nft.recipeID, + LocaleKeys.resolution.tr(): "${widget.nft.width}x${widget.nft.height}", + LocaleKeys.ipfs_cid.tr(): widget.nft.cid + }; case NftType.TYPE_ITEM: - return {LocaleKeys.recipe_id.tr(): widget.nft.recipeID, LocaleKeys.resolution.tr(): widget.nft.getAssetSize(), kIpfsCid: widget.nft.cid}; + return { + LocaleKeys.recipe_id.tr(): widget.nft.recipeID + }; case NftType.TYPE_TRADE: break; } - return {LocaleKeys.recipe_id.tr(): widget.nft.recipeID, LocaleKeys.resolution.tr(): widget.nft.getAssetSize(), kIpfsCid: widget.nft.cid}; + return { + LocaleKeys.recipe_id.tr(): widget.nft.recipeID, + LocaleKeys.resolution.tr(): "${widget.nft.width}x${widget.nft.height}", + LocaleKeys.ipfs_cid.tr(): widget.nft.cid}; } @override @@ -81,9 +86,16 @@ class _TabFieldState extends State { final nftDetail = getNFTDetailsMap(); - final listOwnership = ownership.entries.map((element) => _tabDetails(field: element.key, value: element.value)).toList(); + final listOwnership = ownership.entries.map((element) => _tabDetails(field: element.key, value: element.value, customColor: element.key == LocaleKeys.owner.tr() ? Colors.red : null)).toList(); - final listDetails = nftDetail.entries.map((element) => _tabDetails(field: element.key, value: element.value, customWidget: customWidget(element))).toList(); + final listDetails = nftDetail.entries + .map( + (element) => _tabDetails( + field: element.key, + value: element.value, + customWidget: (element.key == LocaleKeys.recipe_id.tr() || element.key == LocaleKeys.ipfs_cid.tr()) && element.value.isNotEmpty ? _tabDetailsWithIcon(value: element.value) : null), + ) + .toList(); return AnimatedContainer( duration: const Duration(milliseconds: 100), @@ -205,15 +217,15 @@ class _TabFieldState extends State { children: [ Text( value.substring(0, 6), - style: TextStyle(color: AppColors.kWhite), + style: TextStyle(color: AppColors.kGreyColor, fontSize: 9.sp), ), Text( "...", - style: TextStyle(color: AppColors.kWhite), + style: TextStyle(color: AppColors.kGreyColor, fontSize: 9.sp), ), Text( value.substring(value.length - 5, value.length), - style: TextStyle(color: AppColors.kWhite), + style: TextStyle(color: AppColors.kGreyColor, fontSize: 9.sp), ), if (value.isNotEmpty) InkWell( @@ -226,8 +238,8 @@ class _TabFieldState extends State { }, child: Icon( Icons.copy_outlined, - color: AppColors.kWhite, - size: 15.h, + color: AppColors.kGreyColor, + size: 11.h, ), ) ], @@ -242,7 +254,7 @@ class _TabFieldState extends State { flex: 50, child: Text( field, - style: const TextStyle(color: Colors.white), + style: TextStyle(color: AppColors.kGreyColor, fontSize: 9.sp), ), ), if (customWidget != null) ...[ @@ -252,7 +264,7 @@ class _TabFieldState extends State { flex: 45, child: Text( value, - style: TextStyle(color: customColor != null ? AppColors.kPurple : Colors.white), + style: TextStyle(color: customColor != null ? AppColors.kPurple : AppColors.kGreyColor, fontSize: 9.sp), maxLines: 1, overflow: TextOverflow.ellipsis, ), diff --git a/wallet/lib/pages/purchase_item/clipper/top_left_bottom_right_clipper.dart b/wallet/lib/pages/purchase_item/clipper/top_left_bottom_right_clipper.dart new file mode 100644 index 0000000000..446d240b9d --- /dev/null +++ b/wallet/lib/pages/purchase_item/clipper/top_left_bottom_right_clipper.dart @@ -0,0 +1,23 @@ +import 'package:flutter/material.dart'; + +class TopLeftBottomRightClipper extends CustomClipper { + @override + Path getClip(Size size) { + final path = Path(); + + path.lineTo(0, 18); + path.lineTo(0, size.height); + path.lineTo(size.width - 18, size.height); + path.lineTo(size.width, size.height - 18); + path.lineTo(size.width, 0); + path.lineTo(18, 0); + path.lineTo(0, 18); + + return path; + } + + @override + bool shouldReclip(covariant CustomClipper oldClipper) { + return false; + } +} diff --git a/wallet/lib/pages/purchase_item/purchase_item_screen.dart b/wallet/lib/pages/purchase_item/purchase_item_screen.dart index a27194c8e5..35a6011dbe 100644 --- a/wallet/lib/pages/purchase_item/purchase_item_screen.dart +++ b/wallet/lib/pages/purchase_item/purchase_item_screen.dart @@ -18,7 +18,6 @@ import 'package:pylons_wallet/pages/detailed_asset_view/widgets/pdf_viewer.dart' import 'package:pylons_wallet/pages/detailed_asset_view/widgets/tab_fields.dart'; import 'package:pylons_wallet/pages/gestures_for_detail_screen.dart'; import 'package:pylons_wallet/pages/home/currency_screen/model/ibc_coins.dart'; -import 'package:pylons_wallet/pages/owner_purchase_view_common/qr_code_screen.dart'; import 'package:pylons_wallet/pages/purchase_item/clipper/buy_now_clipper.dart'; import 'package:pylons_wallet/pages/purchase_item/purchase_item_view_model.dart' show PurchaseItemViewModel; import 'package:pylons_wallet/pages/purchase_item/widgets/buy_nft_button.dart'; @@ -70,11 +69,12 @@ class _PurchaseItemScreenState extends State { return ChangeNotifierProvider.value( value: viewModel, child: WillPopScope( - onWillPop: () async { - viewModel.destroyPlayers(); - return true; - }, - child: const PurchaseItemContent()), + onWillPop: () async { + viewModel.destroyPlayers(); + return true; + }, + child: const PurchaseItemContent(), + ), ); } } @@ -90,7 +90,6 @@ class PurchaseItemContent extends StatefulWidget { class _PurchaseItemContentState extends State { bool _showPay = false; - final GlobalKey key = GlobalKey(); final myBottomDrawerController = BottomDrawerController(); @@ -146,48 +145,49 @@ class _PurchaseItemContentState extends State { final viewModel = context.watch(); return Scaffold( - backgroundColor: AppColors.kBlack, - body: GesturesForDetailsScreen( - nft: viewModel.nft, - viewModel: viewModel, - screen: DetailScreen.purchaseScreen, - tapUp: (context) => onTapUp, - child: Stack( - children: [ - getTypeWidget(viewModel), - Visibility( - visible: !viewModel.isViewingFullNft, - child: Padding( - padding: EdgeInsets.only(left: 8, right: 8, bottom: 8, top: MediaQuery.of(context).viewPadding.top), - child: SizedBox( - height: 100.h, - width: double.infinity, - child: ListTile( - leading: GestureDetector( - onTap: () { - viewModel.destroyPlayers(); - Navigator.pop(context); - }, - child: SvgPicture.asset( - SVGUtil.OWNER_BACK_ICON, - height: 25.h, - ), + backgroundColor: AppColors.kBlack, + body: GesturesForDetailsScreen( + nft: viewModel.nft, + viewModel: viewModel, + screen: DetailScreen.purchaseScreen, + tapUp: (context) => onTapUp, + child: Stack( + children: [ + getTypeWidget(viewModel), + Visibility( + visible: !viewModel.isViewingFullNft, + child: Padding( + padding: EdgeInsets.only(left: 8.w, right: 8.w, bottom: 8.h, top: MediaQuery.of(context).viewPadding.top.h), + child: SizedBox( + height: 100.h, + width: double.infinity, + child: ListTile( + leading: GestureDetector( + onTap: () { + viewModel.destroyPlayers(); + Navigator.pop(context); + }, + child: SvgPicture.asset( + SVGUtil.OWNER_BACK_ICON, + height: 25.h, ), - trailing: const SizedBox(), ), + trailing: const SizedBox(), ), ), ), - Visibility( - visible: !viewModel.isViewingFullNft, - child: const Align( - alignment: Alignment.bottomCenter, - child: OwnerBottomDrawer(), - ), - ) - ], - ), - )); + ), + Visibility( + visible: !viewModel.isViewingFullNft, + child: const Align( + alignment: Alignment.bottomCenter, + child: OwnerBottomDrawer(), + ), + ) + ], + ), + ), + ); } //detect card's outside tap @@ -251,60 +251,17 @@ class _OwnerBottomDrawerState extends State { if (viewModel.collapsed) ...[ Padding( padding: EdgeInsets.only(left: 16.w, right: 16.w, bottom: 16.w, top: 8.w), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, children: [ - SizedBox( - height: 75.h, - child: Row( - children: [ - Expanded(child: _title(nft: viewModel.nft, owner: viewModel.nft.type == NftType.TYPE_RECIPE ? viewModel.nft.creator : viewModel.nft.owner)), - IconButton( - key: const Key(kKeyboardUpButtonKeyValue), - icon: Icon( - Icons.keyboard_arrow_up, - size: 32.h, - color: Colors.white, - ), - onPressed: () { - viewModel.toChangeCollapse(); - }, - ) - ], - ), - ), - const SizedBox( - height: 10, - ), - getProgressWidget(viewModel), - SizedBox( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ + _title(nft: viewModel.nft, owner: viewModel.nft.type == NftType.TYPE_RECIPE ? viewModel.nft.creator : viewModel.nft.owner), SizedBox( - width: 20.w, - ), - buildLikeColumn(viewModel: viewModel), - SizedBox( - width: 20.w, - ), - GestureDetector( - onTap: () async { - final Size size = MediaQuery.of(context).size; - context.read().shareNFTLink(size: size); - }, - child: Container( - padding: EdgeInsets.only(bottom: 12.h), - child: SvgPicture.asset( - SVGUtil.OWNER_SHARE, - height: 20.h, - ), - ), - ), - SizedBox( - width: 20.w, + height: 18.h, ), - const Spacer(), /// BUY NFT BUTTON if (viewModel.showBuyNowButton(isPlatformAndroid: Platform.isAndroid)) @@ -341,7 +298,58 @@ class _OwnerBottomDrawerState extends State { ), ], ), - ) + ), + Column( + children: [ + SvgPicture.asset( + SVGUtil.OWNER_VIEWS, + width: 20.w, + height: 15.h, + ), + SizedBox( + width: 4.5.w, + ), + Text( + viewModel.viewsCount.toString(), + style: TextStyle(color: Colors.white, fontSize: 11.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), + ), + SizedBox( + height: 5.h, + ), + buildLikeColumn(viewModel: viewModel), + SizedBox( + height: 18.h, + ), + GestureDetector( + onTap: () async { + final Size size = MediaQuery.of(context).size; + context.read().shareNFTLink(size: size); + }, + child: Container( + padding: EdgeInsets.only(bottom: 12.h), + child: SvgPicture.asset( + SVGUtil.OWNER_SHARE, + height: 15.h, + width: 15.w, + ), + ), + ), + SizedBox( + height: 25.h, + ), + IconButton( + key: const Key(kKeyboardUpButtonKeyValue), + icon: Icon( + Icons.keyboard_arrow_up, + size: 28.h, + color: Colors.white, + ), + onPressed: () { + viewModel.toChangeCollapse(); + }, + ) + ], + ), ], ), ) @@ -396,11 +404,11 @@ class _OwnerBottomDrawerState extends State { child: viewModel.isLiking ? getLikingLoader() : getLikeIcon(likedByMe: viewModel.likedByMe)), ), SizedBox( - height: 5.h, + height: 2.8.h, ), Text( viewModel.likesCount.toString(), - style: TextStyle(color: Colors.white, fontSize: 10.sp), + style: TextStyle(color: Colors.white, fontSize: 10.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), ), ], ); @@ -409,7 +417,7 @@ class _OwnerBottomDrawerState extends State { Widget getLikingLoader() { return SizedBox( height: 15.h, - width: 15.h, + width: 15.w, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation(AppColors.kWhite), @@ -419,8 +427,8 @@ class _OwnerBottomDrawerState extends State { Widget getLikeIcon({required bool likedByMe}) { return SizedBox( - height: 20.h, - width: 20.h, + height: 15.h, + width: 15.w, child: Image.asset( 'assets/images/icons/${likedByMe ? 'like_full' : 'like'}.png', fit: BoxFit.fill, @@ -431,6 +439,7 @@ class _OwnerBottomDrawerState extends State { Stack buildOpenedSheet(BuildContext context, PurchaseItemViewModel viewModel) { return Stack( + key: const Key(kPurchaseItemBottomSheetKey), children: [ Align( alignment: Alignment.topRight, @@ -438,22 +447,24 @@ class _OwnerBottomDrawerState extends State { clipper: RightTriangleClipper(orientation: enums.Orientation.Orientation_SW), child: Container( color: AppColors.kDarkRed, - height: 50, - width: 50, + height: 50.h, + width: 50.w, child: Center( - child: IconButton( - alignment: Alignment.topRight, - padding: const EdgeInsets.only( - bottom: 8, - left: 8, + child: IconButton( + key: const Key(kCloseBottomSheetKey), + alignment: Alignment.topRight, + padding: EdgeInsets.only( + bottom: 8.h, + left: 8.w, + ), + icon: const Icon(Icons.keyboard_arrow_down_outlined), + onPressed: () { + viewModel.toChangeCollapse(); + }, + iconSize: 32.h, + color: Colors.white, ), - icon: const Icon(Icons.keyboard_arrow_down_outlined), - onPressed: () { - viewModel.toChangeCollapse(); - }, - iconSize: 32, - color: Colors.white, - )), + ), ), ), ), @@ -482,21 +493,6 @@ class _OwnerBottomDrawerState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ _title(nft: viewModel.nft, owner: viewModel.nft.type == NftType.TYPE_RECIPE ? viewModel.nft.creator : viewModel.nft.owner), - SizedBox( - height: 10.h, - ), - Row( - children: [ - SvgPicture.asset(SVGUtil.OWNER_VIEWS), - SizedBox( - width: 10.w, - ), - Text( - viewModel.viewsCount == 1 ? "${viewModel.viewsCount.toString()} $kView" : "${viewModel.viewsCount.toString()} $kViews", - style: TextStyle(color: Colors.white, fontSize: 12.sp), - ) - ], - ), SizedBox( height: 20.h, ), @@ -522,23 +518,25 @@ class _OwnerBottomDrawerState extends State { ], if (viewModel.nft.hashtags.isNotEmpty) Wrap( - spacing: 10.w, - children: List.generate( - viewModel.hashtagList.length, - (index) => SizedBox( - child: DetectableText( - text: "#${viewModel.hashtagList[index]}", - detectionRegExp: detectionRegExp()!, - detectedStyle: TextStyle( - fontSize: 12.sp, - color: AppColors.kCopyColor, - ), - basicStyle: TextStyle( - fontSize: 20.sp, - ), - onTap: (tappedText) {}, - ), - ))), + spacing: 10.w, + children: List.generate( + viewModel.hashtagList.length, + (index) => SizedBox( + child: DetectableText( + text: "#${viewModel.hashtagList[index]}", + detectionRegExp: detectionRegExp()!, + detectedStyle: TextStyle( + fontSize: 12.sp, + color: AppColors.kCopyColor, + ), + basicStyle: TextStyle( + fontSize: 20.sp, + ), + onTap: (tappedText) {}, + ), + ), + ), + ), SizedBox( height: 10.h, ), @@ -581,7 +579,7 @@ class _OwnerBottomDrawerState extends State { onChangeTab: viewModel.onChangeTab, ), SizedBox(height: 10.h), - if (viewModel.nft.type != NftType.TYPE_RECIPE) + if (viewModel.nft.type == NftType.TYPE_RECIPE && viewModel.nftOwnershipHistoryList.isNotEmpty) TabField( name: LocaleKeys.history.tr(), icon: 'history', @@ -599,51 +597,38 @@ class _OwnerBottomDrawerState extends State { Expanded( flex: 15, child: Column( - crossAxisAlignment: CrossAxisAlignment.end, children: [ - Column( - children: [ - GestureDetector( - onTap: () async { - await viewModel.updateLikeStatus(recipeId: viewModel.nft.recipeID, cookBookID: viewModel.nft.cookbookID); - }, - child: viewModel.isLiking ? getLikingLoader() : getLikeIcon(likedByMe: viewModel.likedByMe), - ), - SizedBox( - height: 5.h, - ), - Text( - viewModel.likesCount.toString(), - style: TextStyle(color: Colors.white, fontSize: 10.sp), - ), - ], + SvgPicture.asset( + SVGUtil.OWNER_VIEWS, + width: 15.w, + height: 15.h, + ), + SizedBox( + height: 4.5.h, + ), + Text( + viewModel.viewsCount.toString(), + style: TextStyle(color: Colors.white, fontSize: 11.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), + ), + SizedBox( + height: 18.h, + ), + GestureDetector( + onTap: () async { + await viewModel.updateLikeStatus(recipeId: viewModel.nft.recipeID, cookBookID: viewModel.nft.cookbookID); + }, + child: viewModel.isLiking ? getLikingLoader() : getLikeIcon(likedByMe: viewModel.likedByMe), + ), + SizedBox( + height: 5.h, + ), + Text( + viewModel.likesCount.toString(), + style: TextStyle(color: Colors.white, fontSize: 10.sp), ), SizedBox( height: 20.h, ), - if (viewModel.isOwner()) - GestureDetector( - onTap: () { - showDialog( - context: context, - builder: (_) => QRCodeScreen( - nft: viewModel.nft, - ), - ); - }, - child: SvgPicture.asset( - SVGUtil.QR_ICON, - height: 20.h, - ), - ) - else - const SizedBox(), - if (viewModel.isOwner()) - SizedBox( - height: 20.h, - ) - else - const SizedBox(), GestureDetector( onTap: () async { final Size size = MediaQuery.of(context).size; @@ -651,7 +636,7 @@ class _OwnerBottomDrawerState extends State { }, child: SvgPicture.asset( SVGUtil.OWNER_SHARE, - height: 20.h, + height: 15.h, ), ), ], @@ -714,21 +699,11 @@ class _OwnerBottomDrawerState extends State { Flexible( child: Text( nft.name, - style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 25.sp), + style: TextStyle(color: Colors.white, fontSize: 18.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), - if (nft.type == NftType.TYPE_RECIPE) - Padding( - padding: EdgeInsets.only( - bottom: 2.h, - ), - child: Text( - ' (${nft.amountMinted} of ${nft.quantity})', - style: TextStyle(color: Colors.white, fontWeight: FontWeight.w700, fontSize: 12.sp), - ), - ), ], ), SizedBox( @@ -739,15 +714,15 @@ class _OwnerBottomDrawerState extends State { children: [ TextSpan( text: LocaleKeys.created_by.tr(), - style: TextStyle(color: Colors.white, fontSize: 18.sp), + style: TextStyle(color: Colors.white, fontSize: 11.sp), ), - TextSpan(text: owner, style: TextStyle(color: const Color(0xFFB6B6E8), fontSize: 18.sp)), + TextSpan(text: owner, style: TextStyle(color: AppColors.kCopyColor, fontSize: 13.sp)), WidgetSpan( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4.0), child: SvgPicture.asset( SVGUtil.OWNER_VERIFIED_ICON, - height: 15.h, + height: 12.h, ), ), ), @@ -794,11 +769,12 @@ class _OwnerBottomDrawerState extends State { ); final TradeCompleteDialog tradeCompleteDialog = TradeCompleteDialog( - model: model, - context: context, - onBackPressed: () { - showReceiptDialog(model); - }); + model: model, + context: context, + onBackPressed: () { + showReceiptDialog(model); + }, + ); tradeCompleteDialog.show(); } diff --git a/wallet/lib/pages/purchase_item/purchase_item_view_model.dart b/wallet/lib/pages/purchase_item/purchase_item_view_model.dart index 75286a7a6a..50203a1957 100644 --- a/wallet/lib/pages/purchase_item/purchase_item_view_model.dart +++ b/wallet/lib/pages/purchase_item/purchase_item_view_model.dart @@ -294,8 +294,8 @@ class PurchaseItemViewModel extends ChangeNotifier { Future nftDataInit({required String recipeId, required String cookBookId, required String itemId}) async { final walletAddress = accountPublicInfo.publicAddress; - if (nft.type != NftType.TYPE_RECIPE) { - final nftOwnershipHistory = await repository.getNftOwnershipHistory(itemId: itemId, cookBookId: cookBookId); + if (nft.type == NftType.TYPE_RECIPE) { + final nftOwnershipHistory = await repository.getNftOwnershipHistoryByCookbookIdAndRecipeId(cookBookId: cookBookId,recipeId: recipeId); if (nftOwnershipHistory.isLeft()) { LocaleKeys.something_wrong.tr().show(); return; diff --git a/wallet/lib/pages/purchase_item/widgets/buy_nft_button.dart b/wallet/lib/pages/purchase_item/widgets/buy_nft_button.dart index 84ee286d62..dfa2c156e8 100644 --- a/wallet/lib/pages/purchase_item/widgets/buy_nft_button.dart +++ b/wallet/lib/pages/purchase_item/widgets/buy_nft_button.dart @@ -2,16 +2,17 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:pylons_wallet/main_prod.dart'; import 'package:pylons_wallet/model/nft.dart'; import 'package:pylons_wallet/pages/home/currency_screen/model/ibc_coins.dart'; -import 'package:pylons_wallet/pages/purchase_item/clipper/buy_now_clipper.dart'; import 'package:pylons_wallet/pages/purchase_item/purchase_item_view_model.dart'; import 'package:pylons_wallet/utils/constants.dart'; -import 'package:pylons_wallet/utils/extension.dart'; +import 'package:pylons_wallet/utils/svg_util.dart'; import '../../../generated/locale_keys.g.dart'; +import '../clipper/top_left_bottom_right_clipper.dart'; class BuyNFTButton extends StatelessWidget { final VoidCallback onTapped; @@ -20,6 +21,8 @@ class BuyNFTButton extends StatelessWidget { const BuyNFTButton({Key? key, required this.onTapped, required this.nft}) : super(key: key); Widget getButtonContent(NFT nft, PurchaseItemViewModel viewModel) { + final double btnHeight = 35.h; + final double btnWidth = isTablet ? 160.w : 200.w; if (double.parse(nft.price) == 0) { return Container( height: 60.h, @@ -57,36 +60,59 @@ class BuyNFTButton extends StatelessWidget { ); } return Container( - height: isTablet ? 65.h : 55.h, - width: isTablet ? 160.w : 200.w, - color: AppColors.kDarkRed.withOpacity(0.8), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.end, + height: btnHeight, + width: btnWidth, + decoration: BoxDecoration( + color: AppColors.kGreyLight.withOpacity(0.5), + ), + child: Row( children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - viewModel.nft.ibcCoins.getAssets(), - Text( - "${"buy_for".tr()} ${viewModel.nft.ibcCoins.getCoinWithProperDenomination(viewModel.nft.price)} ${viewModel.nft.ibcCoins.getTrailingAbbrev()} ", - style: TextStyle(color: Colors.white, fontSize: 16.sp, fontWeight: FontWeight.bold), - ), - ], + Expanded( + flex: 4, + child: Stack( + children: [ + Align( + alignment: Alignment.centerRight, + child: SvgPicture.asset( + SVGUtil.CURVED_CORNER_RED_BG, + height: btnHeight, + fit: BoxFit.fill, + ), + ), + Center( + child: AutoSizeText( + LocaleKeys.buy_now.tr(), + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 12.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), + maxLines: 1, + ), + ), + ], + ), + ), + Expanded( + flex: 3, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + RichText( + text: TextSpan( + text: "\$${nft.ibcCoins.getCoinWithProperDenomination(nft.price)}", + style: TextStyle(color: AppColors.kWhite, fontSize: 10.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), + children: [ + TextSpan( + text: " ${LocaleKeys.ea.tr()}.", + style: TextStyle(color: AppColors.kWhite, fontSize: 10.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), + ) + ]), + ), + Text( + "${nft.quantity - nft.amountMinted} ${LocaleKeys.available.tr()}", + style: TextStyle(color: AppColors.kGreyLight, fontSize: 9.sp, fontWeight: FontWeight.normal, fontFamily: kUniversalFontFamily), + ), + ], + ), ), - if (viewModel.nft.ibcCoins.name == kPylonDenom) - Padding( - padding: EdgeInsets.symmetric(horizontal: 18.0.w), - child: Text( - "(\$${viewModel.nft.ibcCoins.name.convertPylonsToUSD(viewModel.nft.price)} $kStripeUSD_ABR)", - style: TextStyle(color: Colors.white, fontSize: 13.sp), - ), - ) - else - const SizedBox(), - SizedBox( - height: 2.0.h, - ) ], ), ); @@ -96,7 +122,7 @@ class BuyNFTButton extends StatelessWidget { Widget build(BuildContext context) { final viewModel = context.read(); return ClipPath( - clipper: BuyClipper(), + clipper: TopLeftBottomRightClipper(), child: InkWell( onTap: onTapped, child: getButtonContent(nft, viewModel), diff --git a/wallet/lib/pages/purchase_item/widgets/pay_now_dialog.dart b/wallet/lib/pages/purchase_item/widgets/pay_now_dialog.dart index 561da11c6a..58d9cde114 100644 --- a/wallet/lib/pages/purchase_item/widgets/pay_now_dialog.dart +++ b/wallet/lib/pages/purchase_item/widgets/pay_now_dialog.dart @@ -1,10 +1,12 @@ import 'dart:convert'; -import 'package:pylons_wallet/components/buttons/custom_paint_button.dart'; + import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:get_it/get_it.dart'; +import 'package:provider/provider.dart'; +import 'package:pylons_wallet/components/buttons/custom_paint_button.dart'; import 'package:pylons_wallet/components/loading.dart'; import 'package:pylons_wallet/main_prod.dart'; import 'package:pylons_wallet/model/nft.dart'; @@ -25,15 +27,12 @@ import 'package:pylons_wallet/utils/clipper_utils.dart'; import 'package:pylons_wallet/utils/constants.dart'; import 'package:pylons_wallet/utils/enums.dart' as enums; import 'package:pylons_wallet/utils/enums.dart'; -import 'package:pylons_wallet/utils/extension.dart'; import 'package:pylons_wallet/utils/route_util.dart'; -import 'package:provider/provider.dart'; -import 'package:auto_size_text/auto_size_text.dart'; import '../../../generated/locale_keys.g.dart'; -TextStyle _titleTextStyle = TextStyle(color: Colors.white, fontSize: 25.sp, fontWeight: FontWeight.w700); -TextStyle _rowTitleTextStyle = TextStyle(color: Colors.white, fontWeight: FontWeight.w800, fontSize: 13.sp); +TextStyle _titleTextStyle = TextStyle(color: AppColors.kWhite, fontSize: 19.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700); +TextStyle _rowTitleTextStyle = TextStyle(color: Colors.white, fontSize: 12.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700); class PayNowDialog { final NFT nft; @@ -50,6 +49,7 @@ class PayNowDialog { context: buildContext, builder: (context) { return Dialog( + key: const Key(kCheckoutDialogKey), backgroundColor: Colors.transparent, child: ChangeNotifierProvider.value( value: purchaseItemViewModel, @@ -83,7 +83,7 @@ class _PayNowWidgetState extends State { Widget build(BuildContext context) { return Container( color: Colors.black.withOpacity(0.7), - height: 400.h, + height: 300.h, width: isTablet ? 200.w : 270.w, margin: isTablet ? EdgeInsets.symmetric(horizontal: 30.w) : EdgeInsets.zero, child: Stack( @@ -113,15 +113,17 @@ class _PayNowWidgetState extends State { top: 0, bottom: 0, child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, + crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( - height: 30.h, + height: 35.h, + ), + Padding( + padding: EdgeInsets.only(left: 20.w), + child: Text(LocaleKeys.checkout.tr(), textAlign: TextAlign.center, style: _titleTextStyle), ), - Text(LocaleKeys.checkout.tr(), textAlign: TextAlign.center, style: _titleTextStyle), SizedBox( - height: 30.h, + height: 20.h, ), buildRow( subtitle: widget.nft.name, @@ -154,30 +156,24 @@ class _PayNowWidgetState extends State { SizedBox( height: 30.h, ), - Padding( - padding: EdgeInsets.only(left: 20.w), - child: Text( - 'price'.tr(), - style: _rowTitleTextStyle, - ), - ), - SizedBox( - height: 3.h, + buildRow( + subtitle: "\$${widget.nft.ibcCoins.getCoinWithProperDenomination(widget.nft.price)}", + title: LocaleKeys.price.tr(), ), - _buildPriceView(), SizedBox( - height: 60.h, + height: 30.h, ), if (!widget.shouldBuy) Center( child: buildButton( - title: LocaleKeys.add_pylons.tr(), - bgColor: AppColors.kDarkRed, - onPressed: () async { - final navigator = Navigator.of(context); - navigator.pop(); - navigator.pushNamed(RouteUtil.ROUTE_ADD_PYLON); - }), + title: LocaleKeys.add_pylons.tr(), + bgColor: AppColors.kDarkRed, + onPressed: () async { + final navigator = Navigator.of(context); + navigator.pop(); + navigator.pushNamed(RouteUtil.ROUTE_ADD_PYLON); + }, + ), ), if (widget.shouldBuy) Container( @@ -207,20 +203,21 @@ class _PayNowWidgetState extends State { return Row( children: [ Expanded( - child: Padding( - padding: EdgeInsets.only(left: 20.w), - child: Text( - title, - style: _rowTitleTextStyle, + child: Padding( + padding: EdgeInsets.only(left: 20.w), + child: Text( + title, + style: _rowTitleTextStyle, + ), ), - )), + ), Expanded( flex: 2, child: Text( subtitle, maxLines: 1, overflow: TextOverflow.ellipsis, - style: TextStyle(color: subtitleTextColor, fontSize: 15.sp, fontWeight: FontWeight.w600), + style: TextStyle(color: subtitleTextColor, fontSize: 13.sp, fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), ), ), ], @@ -256,62 +253,6 @@ class _PayNowWidgetState extends State { ); } - Widget _buildPriceView() { - return Padding( - padding: EdgeInsets.symmetric(horizontal: 20.w), - child: Row( - children: [ - Expanded( - flex: 2, - child: Container( - height: 40.h, - color: AppColors.kDarkRed, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(width: 12.r, height: 12.r, child: widget.nft.ibcCoins.getSecondaryAssets()), - SizedBox(width: 3.w), - Text( - widget.nft.ibcCoins.getName(), - style: TextStyle(fontSize: 10.sp, color: Colors.white), - ), - ], - ), - ), - ), - Expanded( - flex: 3, - child: Container( - height: 40.h, - color: AppColors.kGreyColor, - child: Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - AutoSizeText( - widget.nft.ibcCoins.getCoinWithProperDenomination(widget.nft.price), - maxLines: 1, - style: TextStyle(fontSize: 15.sp, color: Colors.white, fontWeight: FontWeight.w700), - ), - if (widget.nft.ibcCoins.name == kPylonDenom) - Padding( - padding: EdgeInsets.only(top: 2.w), - child: AutoSizeText( - "(\$${widget.nft.ibcCoins.name.convertPylonsToUSD(widget.nft.price)} $kStripeUSD_ABR)", - maxLines: 1, - style: TextStyle(fontSize: 12.sp, color: Colors.white, fontWeight: FontWeight.w400), - ), - ), - ], - ), - ), - ), - ), - ], - ), - ); - } - Future executeRecipe(BuildContext context) async { final provider = context.read(); final ibcEnumCoins = provider.nft.denom.toIBCCoinsEnum(); @@ -380,15 +321,16 @@ class _PayNowWidgetState extends State { final pi = await Stripe.instance.retrievePaymentIntent(pi_info.clientsecret); await Stripe.instance.initPaymentSheet( - paymentSheetParameters: SetupPaymentSheetParameters( - googlePay: PaymentSheetGooglePay( - merchantCountryCode: kStripeMerchantCountry, - testEnv: baseEnv.baseStripeTestEnv, - ), - applePay: const PaymentSheetApplePay(merchantCountryCode: kStripeMerchantCountry), - style: ThemeMode.system, - merchantDisplayName: kStripeMerchantDisplayName, - paymentIntentClientSecret: pi_info.clientsecret)); + paymentSheetParameters: SetupPaymentSheetParameters( + googlePay: PaymentSheetGooglePay( + merchantCountryCode: kStripeMerchantCountry, + testEnv: baseEnv.baseStripeTestEnv, + ), + applePay: const PaymentSheetApplePay(merchantCountryCode: kStripeMerchantCountry), + style: ThemeMode.system, + merchantDisplayName: kStripeMerchantDisplayName, + paymentIntentClientSecret: pi_info.clientsecret), + ); Navigator.pop(navigatorKey.currentState!.overlay!.context); await Stripe.instance.presentPaymentSheet(); @@ -466,15 +408,16 @@ class _PayNowWidgetState extends State { final pi = await Stripe.instance.retrievePaymentIntent(pi_info.clientsecret); await Stripe.instance.initPaymentSheet( - paymentSheetParameters: SetupPaymentSheetParameters( - style: ThemeMode.system, - googlePay: PaymentSheetGooglePay( - merchantCountryCode: kStripeMerchantCountry, - testEnv: baseEnv.baseStripeTestEnv, - ), - applePay: const PaymentSheetApplePay(merchantCountryCode: kStripeMerchantCountry), - merchantDisplayName: kStripeMerchantDisplayName, - paymentIntentClientSecret: pi_info.clientsecret)); + paymentSheetParameters: SetupPaymentSheetParameters( + style: ThemeMode.system, + googlePay: PaymentSheetGooglePay( + merchantCountryCode: kStripeMerchantCountry, + testEnv: baseEnv.baseStripeTestEnv, + ), + applePay: const PaymentSheetApplePay(merchantCountryCode: kStripeMerchantCountry), + merchantDisplayName: kStripeMerchantDisplayName, + paymentIntentClientSecret: pi_info.clientsecret), + ); Navigator.pop(navigatorKey.currentState!.overlay!.context); await Stripe.instance.presentPaymentSheet(); diff --git a/wallet/lib/pages/purchase_item/widgets/pay_with_swipe.dart b/wallet/lib/pages/purchase_item/widgets/pay_with_swipe.dart index 008e5939b9..d5bed4e3c3 100644 --- a/wallet/lib/pages/purchase_item/widgets/pay_with_swipe.dart +++ b/wallet/lib/pages/purchase_item/widgets/pay_with_swipe.dart @@ -1,6 +1,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:pylons_wallet/utils/constants.dart'; import '../../../generated/locale_keys.g.dart'; @@ -78,7 +79,7 @@ class _PylonsPayWithSwipeState extends State { child: Text( LocaleKeys.swipe_right_to_pay.tr(), textAlign: TextAlign.center, - style: TextStyle(color: Colors.white, fontSize: 14.sp), + style: TextStyle(color: Colors.white, fontSize: 14.sp,fontFamily: kUniversalFontFamily,fontWeight: FontWeight.w700), ), ), ), diff --git a/wallet/lib/services/data_stores/remote_data_store.dart b/wallet/lib/services/data_stores/remote_data_store.dart index 12258c8495..625bb130da 100644 --- a/wallet/lib/services/data_stores/remote_data_store.dart +++ b/wallet/lib/services/data_stores/remote_data_store.dart @@ -126,6 +126,12 @@ abstract class RemoteDataStore { /// else will throw error Future> getNftOwnershipHistory({required String itemId, required String cookBookId}); + /// This method is used to get history of nft owners + /// Input: [cookBookId] and [recipeId] of the NFT + /// Output : [List][NftOwnershipHistory] will contain the list of NftOwnershipHistory data if success + /// else will throw error + Future> getNftOwnershipHistoryByCookbookIdAndRecipeId({required String cookBookId, required String recipeId}); + /// This method is used to get views count of NFT /// Input: [recipeId],[cookBookID] and [walletAddress] of the given NFT /// Output : [int] will contain the views count of the NFT @@ -705,6 +711,32 @@ class RemoteDataStoreImp implements RemoteDataStore { return reverseOrder.toList(); } + @override + Future> getNftOwnershipHistoryByCookbookIdAndRecipeId({required String cookBookId, required String recipeId}) async{ + final baseApiUrl = getBaseEnv().baseApiUrl; + final uri = Uri.parse("$baseApiUrl/pylons/get_recipe_history/$cookBookId/$recipeId"); + + final List historyList = []; + + final historyResponse = await httpClient.get(uri); + + if (historyResponse.statusCode != API_SUCCESS_CODE) { + throw HandlerFactory.ERR_SOMETHING_WENT_WRONG; + } + final historyMap = jsonDecode(historyResponse.body); + + if (historyMap == null) { + throw HandlerFactory.ERR_SOMETHING_WENT_WRONG; + } + historyMap[kHistory].map((e) { + final nft = NftOwnershipHistory.fromCookBookAndRecipeJson(e as Map); + historyList.add(nft); + }).toList(); + + final reverseOrder = historyList.reversed.toList(); + return reverseOrder.toList(); + } + Future _signAndBroadcast(GeneratedMessage message) async { final unsignedTransaction = UnsignedAlanTransaction(messages: [message]); diff --git a/wallet/lib/services/repository/repository.dart b/wallet/lib/services/repository/repository.dart index 97d3bb9bf0..b74adfb541 100644 --- a/wallet/lib/services/repository/repository.dart +++ b/wallet/lib/services/repository/repository.dart @@ -317,6 +317,11 @@ abstract class Repository { /// Output: returns [List][NftOwnershipHistory] if success else this will give [Failure] Future>> getNftOwnershipHistory({required String itemId, required String cookBookId}); + /// This method will get the nft history + /// Input: [cookBookId] and [recipeId] of the nft + /// Output: returns [List][NftOwnershipHistory] if success else this will give [Failure] + Future>> getNftOwnershipHistoryByCookbookIdAndRecipeId({required String cookBookId, required String recipeId}); + /// This method will get the transaction history from the chain /// Input: [address] of the user /// Output: returns [List][TransactionHistory] if success else this will give [Failure] @@ -1820,6 +1825,26 @@ class RepositoryImp implements Repository { } } + @override + Future>> getNftOwnershipHistoryByCookbookIdAndRecipeId({required String cookBookId, required String recipeId}) async{ + if (!await networkInfo.isConnected) { + return Left(NoInternetFailure(LocaleKeys.no_internet.tr())); + } + + try { + final result = await remoteDataStore.getNftOwnershipHistoryByCookbookIdAndRecipeId(cookBookId: cookBookId,recipeId: recipeId); + + return Right(result); + } on String catch (_) { + return Left(FetchNftOwnershipHistoryFailure(message: LocaleKeys.something_wrong.tr())); + } on Failure catch (_) { + return Left(_); + } on Exception catch (_) { + recordErrorInCrashlytics(_); + return Left(FetchNftOwnershipHistoryFailure(message: LocaleKeys.something_wrong.tr())); + } + } + @override Future>> getAllNotificationsMessages({required String walletAddress, required int limit, required int offset}) async { if (!await networkInfo.isConnected) { diff --git a/wallet/lib/utils/constants.dart b/wallet/lib/utils/constants.dart index 8b63a3f7da..d6365ace95 100644 --- a/wallet/lib/utils/constants.dart +++ b/wallet/lib/utils/constants.dart @@ -309,6 +309,8 @@ const kItemId = "id"; const kCookbookId = "cookbook_id"; const kAmount = "amount"; const kCreatedAt = "created_at"; +const kSenderName = "sender_name"; +const kReceiver = "receiver"; const cookbookIdKey = "cookbookId"; const recipeIdKey = "recipeId"; @@ -406,6 +408,9 @@ const kOwnerViewDrawerKeyValue = "ownerview_header"; const kOwnerViewBottomSheetKeyValue = "bottom_sheet"; const kKeyboardUpButtonKeyValue = "keyboard_up_button"; const kExpandedBuyButtonKeyValue = "expanded_buy_button"; +const kCheckoutDialogKey = "checkout_dialog_key"; +const kPurchaseItemBottomSheetKey = "purchase_item_bottom_sheet"; +const kCloseBottomSheetKey = "close_bottom_sheet_key"; Map denomColors = {'upylon': const Color(0xFF5252d5), 'ustripeusd': const Color(0xFF85bb65), 'uusd': const Color(0xFF85bb65)}; diff --git a/wallet/lib/utils/svg_util.dart b/wallet/lib/utils/svg_util.dart index 089327847b..26b6153b4a 100644 --- a/wallet/lib/utils/svg_util.dart +++ b/wallet/lib/utils/svg_util.dart @@ -90,4 +90,6 @@ class SVGUtil { static String TRANSACTION_SUCCESS = "assets/images/svg/transaction_success.svg"; static String TRANSACTION_RETRY = "assets/images/svg/transaction_retry.svg"; static String PYLONS_POINTS_ICON = "assets/images/svg/pylons_points_icon.svg"; + static String BOTTOM_RIGHT_CURVED_GREY_BG = "assets/images/svg/bottom_right_curved_grey_bg.svg"; + static String CURVED_CORNER_RED_BG = "assets/images/svg/curved_corner_red_bg.svg"; } diff --git a/wallet/pubspec.yaml b/wallet/pubspec.yaml index 54a0402ca9..b2607a92a3 100644 --- a/wallet/pubspec.yaml +++ b/wallet/pubspec.yaml @@ -147,6 +147,8 @@ flutter: fonts: - asset: assets/fonts/UniversalSans-600.ttf weight: 600 + - asset: assets/fonts/UniversalSans-750.ttf + weight: 700 diff --git a/wallet/test/mocks/mock_constants.dart b/wallet/test/mocks/mock_constants.dart index 0d0ac6149e..e4679d3b44 100644 --- a/wallet/test/mocks/mock_constants.dart +++ b/wallet/test/mocks/mock_constants.dart @@ -303,7 +303,7 @@ NftOwnershipHistory MOCK_NFT_OWNERSHIP_HISTORY = NftOwnershipHistory( itemID: "ahmad123axd", cookbookID: "Easel_CookBook_auto_cookbook_2022_08_31_152836_312", createdAt: 0, - receiver: "xyz", + receiverID: "xyz", senderName: "abcxyz", ); diff --git a/wallet/test/mocks/mock_repository.dart b/wallet/test/mocks/mock_repository.dart index d6402ea7c8..f055e6cf30 100644 --- a/wallet/test/mocks/mock_repository.dart +++ b/wallet/test/mocks/mock_repository.dart @@ -550,4 +550,10 @@ class MockRepository extends Repository { Future> logUserJourney({required String screenName}) async { return const Right(null); } + + @override + Future>> getNftOwnershipHistoryByCookbookIdAndRecipeId({required String cookBookId, required String recipeId}) { + // TODO: implement getNftOwnershipHistoryByCookbookIdAndRecipeId + throw UnimplementedError(); + } } diff --git a/wallet/test/widget_testing/components/buttons/nft_buy_button_test.dart b/wallet/test/widget_testing/components/buttons/nft_buy_button_test.dart index b6f7dd251c..6481136b58 100644 --- a/wallet/test/widget_testing/components/buttons/nft_buy_button_test.dart +++ b/wallet/test/widget_testing/components/buttons/nft_buy_button_test.dart @@ -1,21 +1,20 @@ import 'dart:io'; +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:get_it/get_it.dart'; import 'package:mockito/mockito.dart'; import 'package:provider/provider.dart'; import 'package:pylons_wallet/generated/locale_keys.g.dart'; -import 'package:pylons_wallet/pages/home/currency_screen/model/ibc_coins.dart'; import 'package:pylons_wallet/pages/purchase_item/purchase_item_screen.dart'; import 'package:pylons_wallet/pages/purchase_item/purchase_item_view_model.dart'; import 'package:pylons_wallet/pages/purchase_item/widgets/buy_nft_button.dart'; import 'package:pylons_wallet/stores/wallet_store.dart'; import 'package:pylons_wallet/utils/constants.dart'; import '../../../mocks/mock_constants.dart'; +import '../../../mocks/mock_wallet_store.dart'; import '../../../mocks/purchase_item_view_model.mocks.dart'; import '../../extension/size_extension.dart'; -import '../../../mocks/mock_wallet_store.dart'; -import 'package:easy_localization/easy_localization.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); @@ -68,8 +67,7 @@ void main() { testWidgets('should show the NFT Buy Button and make sure user is able to tap', (tester) async { int counter = 0; - final buyButtonFinder = - find.text("${LocaleKeys.buy_for.tr()} ${MOCK_NFT_PREMIUM.ibcCoins.getCoinWithProperDenomination(MOCK_NFT_PREMIUM.price)} ${MOCK_NFT_PREMIUM.ibcCoins.getTrailingAbbrev()} "); + final buyButtonFinder = find.text(LocaleKeys.buy_now.tr()); await tester.setScreenSize(); await tester.testAppForWidgetTesting(ChangeNotifierProvider.value( value: viewModel, @@ -90,4 +88,25 @@ void main() { expect(buyButtonFinder, findsOneWidget); expect(counter, 1); }); + + testWidgets("Checkout Dialog should show on Buy Now Button Click", (tester) async { + when(viewModel.collapsed).thenAnswer((realInvocation) => false); + when(viewModel.nft).thenAnswer((realInvocation) => MOCK_NFT_FREE_VIDEO); + when(viewModel.showBuyNowButton(isPlatformAndroid: Platform.isAndroid)).thenAnswer((realInvocation) => true); + await tester.testAppForWidgetTesting( + ChangeNotifierProvider.value( + value: viewModel, + child: PurchaseItemScreen( + nft: viewModel.nft, + ), + ), + ); + await tester.pump(); + final buyNFTButton = find.byKey(const Key(kExpandedBuyButtonKeyValue)); + expect(buyNFTButton, findsOneWidget); + await tester.tap(buyNFTButton); + await tester.pump(); + final checkoutDialog = find.byKey(const Key(kCheckoutDialogKey)); + expect(checkoutDialog, findsOneWidget); + }); } diff --git a/wallet/test/widget_testing/pages/purchase_item/purchase_item_screen_test.dart b/wallet/test/widget_testing/pages/purchase_item/purchase_item_screen_test.dart new file mode 100644 index 0000000000..f75e13f345 --- /dev/null +++ b/wallet/test/widget_testing/pages/purchase_item/purchase_item_screen_test.dart @@ -0,0 +1,44 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:get_it/get_it.dart'; +import 'package:mockito/mockito.dart'; +import 'package:provider/provider.dart'; +import 'package:pylons_wallet/pages/purchase_item/purchase_item_screen.dart'; +import 'package:pylons_wallet/pages/purchase_item/purchase_item_view_model.dart'; +import 'package:pylons_wallet/stores/wallet_store.dart'; +import 'package:pylons_wallet/utils/constants.dart'; + +import '../../../mocks/mock_constants.dart'; +import '../../../mocks/mock_wallet_store.dart'; +import '../../../mocks/purchase_item_view_model.mocks.dart'; +import '../../extension/size_extension.dart'; + +void main(){ + TestWidgetsFlutterBinding.ensureInitialized(); + final WalletsStore walletStore = MockWalletStore(); + final PurchaseItemViewModel viewModel = MockPurchaseItemViewModel(); + GetIt.I.registerLazySingleton(() => walletStore); + GetIt.I.registerLazySingleton(() => viewModel); + + + testWidgets("Purchase Item Screen Bottom Sheet Visibility Test", (tester) async { + + when(viewModel.collapsed).thenAnswer((realInvocation) => false); + when(viewModel.nft).thenAnswer((realInvocation) => MOCK_NFT_FREE_IMAGE); + when(viewModel.showBuyNowButton(isPlatformAndroid: Platform.isAndroid)).thenAnswer((realInvocation) => true); + await tester.testAppForWidgetTesting( + ChangeNotifierProvider.value( + value: viewModel, + child: PurchaseItemScreen( + nft: viewModel.nft, + ), + ), + ); + await tester.pump(); + final bottomSheet = find.byKey(const Key(kPurchaseItemBottomSheetKey)); + expect(bottomSheet, findsOneWidget); + final closeBottomSheetButton = find.byKey(const Key(kCloseBottomSheetKey)); + expect(closeBottomSheetButton, findsOneWidget); + }); +} diff --git a/wallet/test/widget_testing/pages/purchase_item/widgets/pay_now_dialog_test.dart b/wallet/test/widget_testing/pages/purchase_item/widgets/pay_now_dialog_test.dart index c6bfc86e0f..87c3f1d08e 100644 --- a/wallet/test/widget_testing/pages/purchase_item/widgets/pay_now_dialog_test.dart +++ b/wallet/test/widget_testing/pages/purchase_item/widgets/pay_now_dialog_test.dart @@ -1,19 +1,12 @@ import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter_test/flutter_test.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; import 'package:pylons_wallet/pages/purchase_item/widgets/pay_now_dialog.dart'; -import 'package:pylons_wallet/utils/image_util.dart'; + import '../../../../mocks/mock_constants.dart'; import '../../../helpers/size_extensions.dart'; void main() { - testWidgets('should find secondary pylon currency Icon', (tester) async { - final nft = MOCK_NFT_PREMIUM; - await tester.testAppForWidgetTesting(Material(child: PayNowWidget(nft: nft, onPurchaseDone: (_) {}, shouldBuy: false))); - final findSecondaryPylonIcon = find.image(AssetImage(ImageUtil.PYLONS_CURRENCY_TRANSPARENT)); - expect(findSecondaryPylonIcon, findsOneWidget); - }); - testWidgets('Should show swipe to pay button', (tester) async { final nft = MOCK_NFT_PREMIUM; await tester.testAppForWidgetTesting(Material(child: PayNowWidget(nft: nft, onPurchaseDone: (_) {}, shouldBuy: true)));