diff --git a/wallet/lib/ipc/handler/handlers/create_recipe_handler.dart b/wallet/lib/ipc/handler/handlers/create_recipe_handler.dart index 993016d65b..dc1888badd 100644 --- a/wallet/lib/ipc/handler/handlers/create_recipe_handler.dart +++ b/wallet/lib/ipc/handler/handlers/create_recipe_handler.dart @@ -11,6 +11,7 @@ import 'package:pylons_wallet/pages/home/home_provider.dart'; import 'package:pylons_wallet/providers/collections_tab_provider.dart'; import 'package:pylons_wallet/pylons_app.dart'; import 'package:pylons_wallet/stores/wallet_store.dart'; +import 'package:pylons_wallet/utils/constants.dart'; import 'package:pylons_wallet/utils/route_util.dart'; import 'package:pylons_wallet/modules/Pylonstech.pylons.pylons/module/export.dart' as pylons; @@ -38,7 +39,7 @@ class CreateRecipeHandler implements BaseHandler { if (shouldShowNFTPreview()) { final msgObj = pylons.MsgCreateRecipe.create()..mergeFromProto3Json(jsonMap); - if (msgObj.cookbookId.contains('Evently')) { + if (msgObj.cookbookId.contains(kEvently)) { final events = await Events.eventFromRecipeId(msgObj.cookbookId, msgObj.id); if (events != null) { await navigatorKey.currentState!.pushNamed(Routes.eventView.name, arguments: events); diff --git a/wallet/lib/pages/detailed_asset_view/owner_view.dart b/wallet/lib/pages/detailed_asset_view/owner_view.dart index 9cc4eb74b8..c21239642d 100644 --- a/wallet/lib/pages/detailed_asset_view/owner_view.dart +++ b/wallet/lib/pages/detailed_asset_view/owner_view.dart @@ -288,7 +288,7 @@ class _CollapsedBottomMenuState extends State<_CollapsedBottomMenu> { final ibcEnumCoins = viewModel.nft.ibcCoins; /// This change will reflect only for upylon ibcCoins - final coinWithDenom =ibcEnumCoins.getAbbrev() == constants.kPYLN_ABBREVATION + final coinWithDenom = ibcEnumCoins.getAbbrev() == constants.kPYLN_ABBREVATION ? "\$${ibcEnumCoins.pylnToCredit(viewModel.nft.ibcCoins.getCoinWithProperDenomination(viewModel.nft.price))} ${viewModel.nft.ibcCoins.getAbbrev()}" : "${ibcEnumCoins.getCoinWithProperDenomination(viewModel.nft.price)} ${ibcEnumCoins.getAbbrev()}"; @@ -334,9 +334,7 @@ class _CollapsedBottomMenuState extends State<_CollapsedBottomMenu> { children: [ if (viewModel.nft.type != NftType.TYPE_ITEM) Text( - viewModel.nft.price == "0" - ? LocaleKeys.free.tr() - : coinWithDenom, + viewModel.nft.price == "0" ? LocaleKeys.free.tr() : coinWithDenom, style: TextStyle(color: Colors.white, fontSize: 15.sp, fontWeight: FontWeight.bold), ) ], @@ -402,7 +400,7 @@ class __ExpandedBottomMenuState extends State<_ExpandedBottomMenu> { final ibcEnumCoins = viewModel.nft.ibcCoins; // This change will reflect only for upylon ibcCoins - final coinWithDenom = ibcEnumCoins.getAbbrev() == constants.kPYLN_ABBREVATION + final coinWithDenom = ibcEnumCoins.getAbbrev() == constants.kPYLN_ABBREVATION ? "\$${ibcEnumCoins.pylnToCredit(viewModel.nft.ibcCoins.getCoinWithProperDenomination(viewModel.nft.price))} ${viewModel.nft.ibcCoins.getAbbrev()}" : "${ibcEnumCoins.getCoinWithProperDenomination(viewModel.nft.price)} ${ibcEnumCoins.getAbbrev()}"; @@ -664,9 +662,7 @@ class __ExpandedBottomMenuState extends State<_ExpandedBottomMenu> { children: [ if (viewModel.nft.type != NftType.TYPE_ITEM) ...[ Text( - viewModel.nft.price == "0" - ? LocaleKeys.free.tr() - : coinWithDenom, + viewModel.nft.price == "0" ? LocaleKeys.free.tr() : coinWithDenom, style: TextStyle(color: Colors.white, fontSize: 15.sp, fontWeight: FontWeight.bold), ) ] diff --git a/wallet/lib/pages/detailed_asset_view/owner_view_view_model.dart b/wallet/lib/pages/detailed_asset_view/owner_view_view_model.dart index 232c7a990a..743ac368bb 100644 --- a/wallet/lib/pages/detailed_asset_view/owner_view_view_model.dart +++ b/wallet/lib/pages/detailed_asset_view/owner_view_view_model.dart @@ -6,6 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:just_audio/just_audio.dart'; import 'package:pylons_wallet/components/loading.dart'; import 'package:pylons_wallet/model/common.dart'; +import 'package:pylons_wallet/model/event.dart'; import 'package:pylons_wallet/model/nft.dart'; import 'package:pylons_wallet/model/nft_ownership_history.dart'; import 'package:pylons_wallet/pages/detailed_asset_view/widgets/create_trade_bottom_sheet.dart'; @@ -32,6 +33,9 @@ class OwnerViewViewModel extends ChangeNotifier { final VideoPlayerHelper videoPlayerHelper; final ShareHelper shareHelper; + ///* for events + late Events events; + OwnerViewViewModel({ required this.repository, required this.walletsStore, @@ -473,6 +477,19 @@ class OwnerViewViewModel extends ChangeNotifier { }); } + Future shareEventsLink({required Size size}) async { + final address = accountPublicInfo.publicAddress; + + final link = await repository.createDynamicLinkForRecipeEventShare(address: address, events: events); + return link.fold((l) { + LocaleKeys.something_wrong.tr().show(); + return null; + }, (r) { + shareHelper.shareText(text: r, size: size); + return null; + }); + } + Future changeNFTEnabledDisableStatus({required bool enabled}) async { final response = await repository.enableDisableRecipe( cookBookId: CookbookId(nft.cookbookID), diff --git a/wallet/lib/pages/events/events_screen.dart b/wallet/lib/pages/events/events_screen.dart index 158c2dbc27..34144bad08 100644 --- a/wallet/lib/pages/events/events_screen.dart +++ b/wallet/lib/pages/events/events_screen.dart @@ -2,11 +2,12 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:get_it/get_it.dart'; +import 'package:provider/provider.dart'; import 'package:pylons_wallet/components/space_widgets.dart'; +import 'package:pylons_wallet/model/event.dart'; +import 'package:pylons_wallet/pages/detailed_asset_view/owner_view_view_model.dart'; import 'package:pylons_wallet/utils/constants.dart'; -import 'package:shimmer_animation/shimmer_animation.dart'; - -import '../../model/event.dart'; class EventPassViewScreen extends StatefulWidget { const EventPassViewScreen({super.key, required this.events}); @@ -18,8 +19,31 @@ class EventPassViewScreen extends StatefulWidget { } class _EventPassViewScreenState extends State { + OwnerViewViewModel ownerViewViewModel = GetIt.I.get(); + + @override + void initState() { + super.initState(); + ownerViewViewModel.events = widget.events; + } + @override Widget build(BuildContext context) { + return ChangeNotifierProvider.value( + value: ownerViewViewModel, + builder: (_, __) => const EventPassViewContent(), + ); + } +} + +class EventPassViewContent extends StatelessWidget { + const EventPassViewContent({ + super.key, + }); + + @override + Widget build(BuildContext context) { + final viewModel = context.watch(); return ColoredBox( color: AppColors.kBlack87, child: SafeArea( @@ -44,7 +68,13 @@ class _EventPassViewScreenState extends State { color: AppColors.kWhite, ), ), - SvgPicture.asset(shareIcon), + GestureDetector( + onTap: () { + final Size size = MediaQuery.of(context).size; + viewModel.shareEventsLink(size: size); + }, + child: SvgPicture.asset(shareIcon), + ), ], ), ), @@ -59,7 +89,7 @@ class _EventPassViewScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - widget.events.eventName, + viewModel.events.eventName, style: Theme.of(context).textTheme.displayLarge?.copyWith(fontSize: 25.sp, fontWeight: FontWeight.w700, color: AppColors.kWhite), ), VerticalSpace(20.h), @@ -74,7 +104,7 @@ class _EventPassViewScreenState extends State { style: Theme.of(context).textTheme.displayLarge?.copyWith(fontSize: 11.sp, fontWeight: FontWeight.w400, color: AppColors.kWhite), ), Text( - widget.events.startDate, + viewModel.events.startDate, style: Theme.of(context).textTheme.labelSmall?.copyWith(fontSize: 15.sp, fontWeight: FontWeight.w700, color: AppColors.kWhite), ), ], @@ -87,7 +117,7 @@ class _EventPassViewScreenState extends State { style: Theme.of(context).textTheme.displayLarge?.copyWith(fontSize: 11.sp, fontWeight: FontWeight.w400, color: AppColors.kWhite), ), Text( - widget.events.startDate, + viewModel.events.startTime, style: Theme.of(context).textTheme.labelSmall?.copyWith(fontSize: 15.sp, fontWeight: FontWeight.w700, color: AppColors.kWhite), ), ], @@ -106,7 +136,7 @@ class _EventPassViewScreenState extends State { style: Theme.of(context).textTheme.displayLarge?.copyWith(fontSize: 11.sp, fontWeight: FontWeight.w400, color: AppColors.kWhite), ), Text( - widget.events.location, + viewModel.events.location, style: Theme.of(context).textTheme.labelSmall?.copyWith(fontSize: 15.sp, fontWeight: FontWeight.w700, color: AppColors.kWhite), ), ], @@ -115,11 +145,11 @@ class _EventPassViewScreenState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - 'SEAT', + 'PRICE', style: Theme.of(context).textTheme.displayLarge?.copyWith(fontSize: 11.sp, fontWeight: FontWeight.w400, color: AppColors.kWhite), ), Text( - "no seat", + viewModel.events.price == "0" ? "Free" : viewModel.events.price, style: Theme.of(context).textTheme.labelSmall?.copyWith(fontSize: 15.sp, fontWeight: FontWeight.w700, color: AppColors.kWhite), ), ], @@ -143,7 +173,7 @@ class _EventPassViewScreenState extends State { SvgPicture.asset(kDiamondIcon), SizedBox(width: 5.w), Text( - 'x ${widget.events.listOfPerks?.length}', + 'x ${viewModel.events.listOfPerks?.length}', style: TextStyle(fontSize: 15.sp, color: AppColors.kWhite, fontWeight: FontWeight.bold), ), SizedBox(width: 5.w), @@ -164,7 +194,7 @@ class _EventPassViewScreenState extends State { margin: EdgeInsets.symmetric(horizontal: 20.w), child: CachedNetworkImage( fit: BoxFit.fill, - imageUrl: widget.events.thumbnail, + imageUrl: viewModel.events.thumbnail, errorWidget: (a, b, c) => const Center( child: Icon( Icons.error_outline, diff --git a/wallet/lib/pages/home/collection_screen/collection_screen.dart b/wallet/lib/pages/home/collection_screen/collection_screen.dart index 37fdabbc15..af79b539bf 100644 --- a/wallet/lib/pages/home/collection_screen/collection_screen.dart +++ b/wallet/lib/pages/home/collection_screen/collection_screen.dart @@ -7,16 +7,17 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:provider/provider.dart'; import 'package:pylons_wallet/components/loading.dart'; import 'package:pylons_wallet/gen/assets.gen.dart'; +import 'package:pylons_wallet/model/event.dart'; import 'package:pylons_wallet/model/nft.dart'; import 'package:pylons_wallet/pages/home/collection_screen/collection_view_model.dart'; import 'package:pylons_wallet/pages/home/collection_screen/widgets/creation_collection_sheet.dart'; import 'package:pylons_wallet/pages/home/collection_screen/widgets/show_recipe_json.dart'; import 'package:pylons_wallet/providers/items_provider.dart'; import 'package:pylons_wallet/providers/recipes_provider.dart'; +import 'package:pylons_wallet/pylons_app.dart'; import 'package:pylons_wallet/utils/constants.dart'; import 'package:pylons_wallet/utils/enums.dart'; import 'package:pylons_wallet/utils/route_util.dart'; - import '../../../providers/collections_tab_provider.dart'; import 'widgets/purchase_collection_sheet.dart'; import 'widgets/trades_collection_sheet.dart'; @@ -181,9 +182,17 @@ class NONNftCreations extends StatelessWidget { padding: EdgeInsets.symmetric(horizontal: 16.w), itemBuilder: (context, index) => InkWell( onTap: () { + final recipe = viewModel.nonNFTRecipes[index]; + + if (recipe.cookbookId.contains(kEvently)) { + final events = Events.fromRecipe(recipe); + navigatorKey.currentState!.pushNamed(Routes.eventView.name, arguments: events); + return; + } + final showRecipeJsonDialog = ShowRecipeJsonDialog( context: context, - recipe: viewModel.nonNFTRecipes[index], + recipe: recipe, ); showRecipeJsonDialog.show(); }, diff --git a/wallet/lib/services/data_stores/remote_data_store.dart b/wallet/lib/services/data_stores/remote_data_store.dart index b0a2be6dac..27b375f826 100644 --- a/wallet/lib/services/data_stores/remote_data_store.dart +++ b/wallet/lib/services/data_stores/remote_data_store.dart @@ -17,6 +17,7 @@ import 'package:protobuf/protobuf.dart'; import 'package:pylons_wallet/ipc/handler/handler_factory.dart'; import 'package:pylons_wallet/model/amount.dart'; import 'package:pylons_wallet/model/balance.dart'; +import 'package:pylons_wallet/model/event.dart'; import 'package:pylons_wallet/model/execution_list_by_recipe_response.dart'; import 'package:pylons_wallet/model/export.dart'; import 'package:pylons_wallet/model/nft.dart'; @@ -88,8 +89,7 @@ abstract class RemoteDataStore { /// Input: [StripeGetLoginBasedOnAddressRequest] the request parameters that are required for the login link /// Output : [StripeGetLoginBasedOnAddressResponse] contains the response for the login link /// else will through error - Future getLoginLinkBasedOnAddress( - {required StripeGetLoginBasedOnAddressRequest req}); + Future getLoginLinkBasedOnAddress({required StripeGetLoginBasedOnAddressRequest req}); /// This method will return the ibc coin info /// Input: [ibcHash] hash of the ibc coin @@ -117,8 +117,7 @@ abstract class RemoteDataStore { /// and [offset] is the last item's position /// Output: if successful will return [List][NotificationMessage] the list of the NotificationMessage /// else will throw error - Future> getAllNotificationMessages( - {required String walletAddress, required int limit, required int offset}); + Future> getAllNotificationMessages({required String walletAddress, required int limit, required int offset}); /// This method will update the recipe in the chain /// Input: [updateRecipeModel] contains the info regarding the recipe update @@ -292,8 +291,7 @@ abstract class RemoteDataStore { /// This method will create dynamic link for the nft share purchase /// Input : [address] the address & [itemId] the id of the item& [cookbookId] against which the invite link to be generated /// Output: [String] return the generated dynamic link else will throw error - Future createDynamicLinkForItemNftShare( - {required String address, required String itemId, required String cookbookId}); + Future createDynamicLinkForItemNftShare({required String address, required String itemId, required String cookbookId}); /// This method will create User account based on account public info /// Input: [publicInfo] contains info related to user chain address, [walletCreationModel] contains user entered data, [appCheckToken] the app specific token, [referralToken] the invitee user address @@ -358,6 +356,11 @@ abstract class RemoteDataStore { Future createTrade({required pylons.MsgCreateTrade msgCreateTrade}); Future> getPylonItem({required Address address}); + + /// This method will create dynamic link for the event share recipe + /// Input : [address] the address & [Event] against which the invite link to be generated + /// Output: [String] return the generated dynamic link else will throw error + Future createDynamicLinkForRecipeEventShare({required String address, required Events events}); } class RemoteDataStoreImp implements RemoteDataStore { @@ -525,17 +528,14 @@ class RemoteDataStoreImp implements RemoteDataStore { @override Future generateStripeRegistrationToken({required String address}) async { final baseEnv = getBaseEnv(); - final response = await httpClient - .get(Uri.parse("${baseEnv.baseStripeUrl}/generate-registration-token?address=$address")) - .timeout( + final response = await httpClient.get(Uri.parse("${baseEnv.baseStripeUrl}/generate-registration-token?address=$address")).timeout( timeOutDuration, ); log(response.body, name: "Stripe | generateStripeRegistrationToken"); if (response.statusCode == API_SUCCESS_CODE) { - return StripeGenerateRegistrationTokenResponse.fromJson( - json.decode(utf8.decode(response.bodyBytes)) as Map); + return StripeGenerateRegistrationTokenResponse.fromJson(json.decode(utf8.decode(response.bodyBytes)) as Map); } if (response.statusCode == API_ERROR_CODE && response.body == 'account already exists\n') { @@ -555,8 +555,7 @@ class RemoteDataStoreImp implements RemoteDataStore { .timeout(timeOutDuration); if (response.statusCode == API_SUCCESS_CODE) { - return StripeGenerateUpdateTokenResponse.fromJson( - json.decode(utf8.decode(response.bodyBytes)) as Map); + return StripeGenerateUpdateTokenResponse.fromJson(json.decode(utf8.decode(response.bodyBytes)) as Map); } log(response.body, name: "Stripe | generateUpdateToken"); @@ -585,8 +584,7 @@ class RemoteDataStoreImp implements RemoteDataStore { } @override - Future getAccountLinkBasedOnUpdateToken( - {required StripeUpdateAccountRequest req}) async { + Future getAccountLinkBasedOnUpdateToken({required StripeUpdateAccountRequest req}) async { final baseEnv = getBaseEnv(); final response = await httpClient .post( @@ -624,8 +622,7 @@ class RemoteDataStoreImp implements RemoteDataStore { } @override - Future getLoginLinkBasedOnAddress( - {required StripeGetLoginBasedOnAddressRequest req}) async { + Future getLoginLinkBasedOnAddress({required StripeGetLoginBasedOnAddressRequest req}) async { final baseEnv = getBaseEnv(); final response = await httpClient .post( @@ -637,8 +634,7 @@ class RemoteDataStoreImp implements RemoteDataStore { log(response.body, name: "Stripe | getLoginLinkBasedOnAddress"); if (response.statusCode == API_SUCCESS_CODE) { - return StripeGetLoginBasedOnAddressResponse.from( - json.decode(utf8.decode(response.bodyBytes)) as Map); + return StripeGetLoginBasedOnAddressResponse.from(json.decode(utf8.decode(response.bodyBytes)) as Map); } throw HandlerFactory.ERR_SOMETHING_WENT_WRONG; @@ -716,8 +712,7 @@ class RemoteDataStoreImp implements RemoteDataStore { for (final ibcHashResult in ibcHashResults) { final relatedBalance = response.balances.firstWhere((element) => element.denom == "ibc/${ibcHashResult.ibcHash}"); - balances.add(Balance( - denom: ibcHashResult.denomTrace.baseDenom.name, amount: Amount(Decimal.parse(relatedBalance.amount)))); + balances.add(Balance(denom: ibcHashResult.denomTrace.baseDenom.name, amount: Amount(Decimal.parse(relatedBalance.amount)))); } return balances; @@ -745,8 +740,7 @@ class RemoteDataStoreImp implements RemoteDataStore { } @override - Future> getAllNotificationMessages( - {required String walletAddress, required int limit, required int offset}) async { + Future> getAllNotificationMessages({required String walletAddress, required int limit, required int offset}) async { final baseApiUrl = getBaseEnv().baseMongoUrl; final uri = Uri.parse("$baseApiUrl/api/notifications/getAllNotifications/$walletAddress/$limit/$offset"); @@ -907,18 +901,20 @@ class RemoteDataStoreImp implements RemoteDataStore { @override Future getRecipe({required CookbookId cookBookId, required RecipeId recipeId}) async { - - try{ + try { const retry = RetryOptions(); - final response = await retry.retry(()async { - final pylons.QueryClient queryClient = getQueryClient(); - final request = pylons.QueryGetRecipeRequest.create() - ..cookbookId = cookBookId.toString() - ..id = recipeId.toString(); - - final response = await queryClient.recipe(request); - return response; - }, retryIf: (_) => true ,); + final response = await retry.retry( + () async { + final pylons.QueryClient queryClient = getQueryClient(); + final request = pylons.QueryGetRecipeRequest.create() + ..cookbookId = cookBookId.toString() + ..id = recipeId.toString(); + + final response = await queryClient.recipe(request); + return response; + }, + retryIf: (_) => true, + ); if (response.hasRecipe()) { return response.recipe; @@ -972,23 +968,25 @@ class RemoteDataStoreImp implements RemoteDataStore { @override Future getCookbookBasedOnId({required String cookBookId}) async { - try{ + try { const retry = RetryOptions(); - final response = await retry.retry(()async { - final pylons.QueryClient queryClient = getQueryClient(); - final request = pylons.QueryGetCookbookRequest.create()..id = cookBookId; + final response = await retry.retry( + () async { + final pylons.QueryClient queryClient = getQueryClient(); + final request = pylons.QueryGetCookbookRequest.create()..id = cookBookId; - final response = await queryClient.cookbook(request); - return response; - }, retryIf: (_) => true,); + final response = await queryClient.cookbook(request); + return response; + }, + retryIf: (_) => true, + ); if (response.hasCookbook()) { return response.cookbook; } throw CookBookNotFoundFailure(LocaleKeys.cookbook_not_found.tr()); - } catch (_) { throw CookBookNotFoundFailure(LocaleKeys.cookbook_not_found.tr()); } @@ -1010,16 +1008,14 @@ class RemoteDataStoreImp implements RemoteDataStore { } @override - Future getExecutionsByRecipeId( - {required String cookBookId, required String recipeId}) async { + Future getExecutionsByRecipeId({required String cookBookId, required String recipeId}) async { final pylons.QueryClient queryClient = getQueryClient(); final queryExecutionListByRecipe = pylons.QueryListExecutionsByRecipeRequest() ..cookbookId = cookBookId ..recipeId = recipeId; final response = await queryClient.listExecutionsByRecipe(queryExecutionListByRecipe); - return ExecutionListByRecipeResponse( - completedExecutions: response.completedExecutions, pendingExecutions: response.pendingExecutions); + return ExecutionListByRecipeResponse(completedExecutions: response.completedExecutions, pendingExecutions: response.pendingExecutions); } @override @@ -1063,8 +1059,7 @@ class RemoteDataStoreImp implements RemoteDataStore { } @override - Future updateFcmToken( - {required String address, required String fcmToken, required String appCheckToken}) async { + Future updateFcmToken({required String address, required String fcmToken, required String appCheckToken}) async { final baseApiUrl = getBaseEnv().baseMongoUrl; final uri = Uri.parse("$baseApiUrl/api/fcmtoken/update/$address/$fcmToken"); @@ -1088,9 +1083,7 @@ class RemoteDataStoreImp implements RemoteDataStore { final uri = Uri.parse("$baseApiUrl/api/notifications/markread"); - final response = await httpClient.post(uri, - headers: {FIREBASE_APP_CHECK_HEADER: appCheckToken, 'Content-type': 'application/json'}, - body: jsonEncode({kNotificationsIds: idsList})); + final response = await httpClient.post(uri, headers: {FIREBASE_APP_CHECK_HEADER: appCheckToken, 'Content-type': 'application/json'}, body: jsonEncode({kNotificationsIds: idsList})); if (response.statusCode == API_SUCCESS_CODE) { final historyMap = jsonDecode(response.body); @@ -1157,8 +1150,7 @@ class RemoteDataStoreImp implements RemoteDataStore { @override Future sendGoogleInAppPurchaseCoinsRequest(GoogleInAppPurchaseModel googleInAppPurchaseModel) async { - final msgGoogleInAPPPurchase = pylons.MsgGoogleInAppPurchaseGetCoins() - ..mergeFromProto3Json(googleInAppPurchaseModel.toJson()); + final msgGoogleInAPPPurchase = pylons.MsgGoogleInAppPurchaseGetCoins()..mergeFromProto3Json(googleInAppPurchaseModel.toJson()); final customTransactionSigningGateway = getCustomTransactionSigningGateway(); @@ -1224,31 +1216,27 @@ class RemoteDataStoreImp implements RemoteDataStore { @override Future createDynamicLinkForRecipeNftShare({required String address, required NFT nft}) async { - final updateText = nft.ibcCoins.getAbbrev() == constants.kPYLN_ABBREVATION? - "\$${nft.ibcCoins.pylnToCredit(nft.ibcCoins.getCoinWithProperDenomination(nft.price))}" + final updateText = nft.ibcCoins.getAbbrev() == constants.kPYLN_ABBREVATION + ? "\$${nft.ibcCoins.pylnToCredit(nft.ibcCoins.getCoinWithProperDenomination(nft.price))}" : "${nft.ibcCoins.getCoinWithProperDenomination(nft.price)} ${nft.ibcCoins.getAbbrev()}"; final dynamicLinkParams = DynamicLinkParameters( - link: Uri.parse("$bigDipperBaseLink?recipe_id=${nft.recipeID}&cookbook_id=${nft.cookbookID}&address=$address"), - uriPrefix: kDeepLink, - androidParameters: AndroidParameters( - packageName: packageName, - fallbackUrl: - Uri.parse("$bigDipperBaseLink?recipe_id=${nft.recipeID}&cookbook_id=${nft.cookbookID}&address=$address"), - ), - iosParameters: IOSParameters( - bundleId: bundleId, - fallbackUrl: - Uri.parse("$bigDipperBaseLink?recipe_id=${nft.recipeID}&cookbook_id=${nft.cookbookID}&address=$address"), - ), - navigationInfoParameters: const NavigationInfoParameters(forcedRedirectEnabled: true), - socialMetaTagParameters: SocialMetaTagParameters( - title: nft.name, - imageUrl: Uri.parse(nft.url), - description: '${nft.description} Price:${nft.price == "0" ? LocaleKeys.free.tr() :updateText}' - , - ) - ); + link: Uri.parse("$bigDipperBaseLink?recipe_id=${nft.recipeID}&cookbook_id=${nft.cookbookID}&address=$address"), + uriPrefix: kDeepLink, + androidParameters: AndroidParameters( + packageName: packageName, + fallbackUrl: Uri.parse("$bigDipperBaseLink?recipe_id=${nft.recipeID}&cookbook_id=${nft.cookbookID}&address=$address"), + ), + iosParameters: IOSParameters( + bundleId: bundleId, + fallbackUrl: Uri.parse("$bigDipperBaseLink?recipe_id=${nft.recipeID}&cookbook_id=${nft.cookbookID}&address=$address"), + ), + navigationInfoParameters: const NavigationInfoParameters(forcedRedirectEnabled: true), + socialMetaTagParameters: SocialMetaTagParameters( + title: nft.name, + imageUrl: Uri.parse(nft.url), + description: '${nft.description} Price:${nft.price == "0" ? LocaleKeys.free.tr() : updateText}', + )); final link = await dynamicLinksGenerator.buildShortLink( dynamicLinkParams, @@ -1280,9 +1268,7 @@ class RemoteDataStoreImp implements RemoteDataStore { final unsignedTransaction = UnsignedAlanTransaction(messages: [msgObj]); - final result = await customTransactionSigningGateway - .signTransaction(transaction: unsignedTransaction, walletLookupKey: walletLookupKey) - .mapError((error) { + final result = await customTransactionSigningGateway.signTransaction(transaction: unsignedTransaction, walletLookupKey: walletLookupKey).mapError((error) { throw error; }).flatMap( (signed) => customTransactionSigningGateway.broadcastTransaction( @@ -1328,9 +1314,7 @@ class RemoteDataStoreImp implements RemoteDataStore { final dynamicLinkParams = DynamicLinkParameters( link: Uri.parse("$bigDipperBaseLink?item_id=$itemId&cookbook_id=$cookbookId&address=$address"), uriPrefix: kDeepLink, - androidParameters: AndroidParameters( - packageName: packageName, - fallbackUrl: Uri.parse("$bigDipperBaseLink?item_id=$itemId&cookbook_id=$cookbookId&address=$address")), + androidParameters: AndroidParameters(packageName: packageName, fallbackUrl: Uri.parse("$bigDipperBaseLink?item_id=$itemId&cookbook_id=$cookbookId&address=$address")), iosParameters: const IOSParameters(bundleId: bundleId), ); @@ -1343,8 +1327,7 @@ class RemoteDataStoreImp implements RemoteDataStore { final dynamicLinkParams = DynamicLinkParameters( link: Uri.parse("$bigDipperBaseLink?trade_id=$tradeId&address=$address"), uriPrefix: kDeepLink, - androidParameters: AndroidParameters( - packageName: packageName, fallbackUrl: Uri.parse("$bigDipperBaseLink?trade_id=$tradeId&address=$address")), + androidParameters: AndroidParameters(packageName: packageName, fallbackUrl: Uri.parse("$bigDipperBaseLink?trade_id=$tradeId&address=$address")), iosParameters: const IOSParameters(bundleId: bundleId), ); @@ -1452,7 +1435,7 @@ class RemoteDataStoreImp implements RemoteDataStore { final OnLogError onLogError; @override - Future> getPylonItem({required Address address}) async{ + Future> getPylonItem({required Address address}) async { final baseApiUrl = getBaseEnv().baseApiUrl; final uri = Uri.parse("$baseApiUrl/pylons/items/${address.id}"); @@ -1465,15 +1448,43 @@ class RemoteDataStoreImp implements RemoteDataStore { final pylonItemsMap = jsonDecode(pylonItemsResponse.body); - final List pylonListItems= []; + final List pylonListItems = []; pylonItemsMap["items"].map((data) { - final pylonItems= PylonItems.fromJson(data as Map); - pylonListItems.add(pylonItems); + final pylonItems = PylonItems.fromJson(data as Map); + pylonListItems.add(pylonItems); }).toList(); return pylonListItems.toList(); } + + @override + Future createDynamicLinkForRecipeEventShare({required String address, required Events events}) async { + final updateText = '${events.eventName} is hosted by ${events.hostName} at location ${events.location} ticket price is ${events.price}'; + final dynamicLinkParams = DynamicLinkParameters( + link: Uri.parse("$bigDipperBaseLink?recipe_id=${events.recipeID}&cookbook_id=${events.cookbookID}&address=$address"), + uriPrefix: kDeepLink, + androidParameters: AndroidParameters( + packageName: packageName, + fallbackUrl: Uri.parse("$bigDipperBaseLink?recipe_id=${events.recipeID}&cookbook_id=${events.cookbookID}&address=$address"), + ), + iosParameters: IOSParameters( + bundleId: bundleId, + fallbackUrl: Uri.parse("$bigDipperBaseLink?recipe_id=${events.recipeID}&cookbook_id=${events.cookbookID}&address=$address"), + ), + navigationInfoParameters: const NavigationInfoParameters(forcedRedirectEnabled: true), + socialMetaTagParameters: SocialMetaTagParameters( + title: events.eventName, + imageUrl: Uri.parse(events.thumbnail), + description: '${events.description} Price:${events.price == "0" ? LocaleKeys.free.tr() : updateText}', + )); + + final link = await dynamicLinksGenerator.buildShortLink( + dynamicLinkParams, + shortLinkType: ShortDynamicLinkType.unguessable, + ); + return link.shortUrl.toString(); + } } class AppleInAppPurchaseModel { @@ -1495,8 +1506,7 @@ class AppleInAppPurchaseModel { receiptData = json['receiptDataBase64'] as String, creator = json['creator'] as String; - Map toJson() => - {"productId": productID, "purchaseId": purchaseID, "receiptDataBase64": receiptData, "creator": creator}; + Map toJson() => {"productId": productID, "purchaseId": purchaseID, "receiptDataBase64": receiptData, "creator": creator}; } class GoogleInAppPurchaseModel { @@ -1521,23 +1531,42 @@ class GoogleInAppPurchaseModel { signature = json['signature'] as String, creator = json['creator'] as String; - Map toJson() => { - "product_id": productID, - "purchase_token": purchaseToken, - "receipt_data_base64": getReceiptDataInBase64(), - "signature": signature, - "creator": creator - }; - - Map toJsonLocalRetry() => { - "product_id": productID, - "purchase_token": purchaseToken, - "receipt_data_base64": receiptData, - "signature": signature, - "creator": creator - }; + Map toJson() => {"product_id": productID, "purchase_token": purchaseToken, "receipt_data_base64": getReceiptDataInBase64(), "signature": signature, "creator": creator}; + + Map toJsonLocalRetry() => {"product_id": productID, "purchase_token": purchaseToken, "receipt_data_base64": receiptData, "signature": signature, "creator": creator}; String getReceiptDataInBase64() { return base64Url.encode(utf8.encode(jsonEncode(receiptData))); } } + +class EventlyDenom { + final String name; + final String symbol; + final String icon; + + EventlyDenom({required this.name, required this.symbol, required this.icon}); + + factory EventlyDenom.initial() { + return EventlyDenom(icon: '', name: '', symbol: ''); + } + + @override + String toString() { + return '{name: $name, symbol: $symbol, icon: $icon}'; + } + + Map toJson() { + final Map map = {}; + map['name'] = name; + map['symbol'] = symbol; + map['icon'] = icon; + return map; + } + + factory EventlyDenom.fromJson(Map json) => EventlyDenom( + name: json['name']!, + symbol: json['symbol']!, + icon: json['icon']!, + ); +} diff --git a/wallet/lib/services/repository/repository.dart b/wallet/lib/services/repository/repository.dart index f12b0f879d..3deae3e142 100644 --- a/wallet/lib/services/repository/repository.dart +++ b/wallet/lib/services/repository/repository.dart @@ -11,6 +11,7 @@ import 'package:internet_connection_checker/internet_connection_checker.dart'; import 'package:local_auth/local_auth.dart'; import 'package:pylons_wallet/components/loading.dart'; import 'package:pylons_wallet/model/balance.dart'; +import 'package:pylons_wallet/model/event.dart'; import 'package:pylons_wallet/model/execution_list_by_recipe_response.dart'; import 'package:pylons_wallet/model/export.dart'; import 'package:pylons_wallet/model/nft.dart'; @@ -581,6 +582,11 @@ abstract class Repository { Future> cancelTrade({required TradeId tradeId, required Address address}); Future>> getPylonItem({required Address address}); + + /// This method will create dynamic link for the event share recipe + /// Input : [address] the address against which the invite link to be generated, [Events] the event whose link to be created + /// Output: [String] return the generated dynamic link else will return [Failure] + Future> createDynamicLinkForRecipeEventShare({required String address, required Events events}); } class RepositoryImp implements Repository { @@ -913,8 +919,7 @@ class RepositoryImp implements Repository { ); return Left(StripeFailure(result.error ?? GEN_PAYMENTRECEIPT_FAILED)); } - await saveTransactionRecord( - transactionHash: "", transactionStatus: TransactionStatus.Success, txLocalModel: localTransactionModel); + await saveTransactionRecord(transactionHash: "", transactionStatus: TransactionStatus.Success, txLocalModel: localTransactionModel); return Right(StripeGeneratePaymentReceiptResponse.from(result)); } on Exception catch (error) { await saveTransactionRecord( @@ -2450,13 +2455,22 @@ class RepositoryImp implements Repository { final BaseEnv Function() getBaseEnv; @override - Future>> getPylonItem({required Address address}) async{ + Future>> getPylonItem({required Address address}) async { try { - final response = await remoteDataStore.getPylonItem(address: address); - return Right(response); + final response = await remoteDataStore.getPylonItem(address: address); + return Right(response); } on Exception catch (e) { recordErrorInCrashlytics(e); return Left(ServerFailure(e.toString())); } } + + @override + Future> createDynamicLinkForRecipeEventShare({required String address, required Events events}) async { + try { + return Right(await remoteDataStore.createDynamicLinkForRecipeEventShare(address: address, events: events)); + } on Exception catch (_) { + return Left(FirebaseDynamicLinkFailure(LocaleKeys.dynamic_link_failure.tr())); + } + } } diff --git a/wallet/lib/utils/constants.dart b/wallet/lib/utils/constants.dart index 7079f3a522..3d005d1ede 100644 --- a/wallet/lib/utils/constants.dart +++ b/wallet/lib/utils/constants.dart @@ -501,3 +501,5 @@ const String drawerKey = "drawer_key"; const String kRemaining = 'remaining'; const kTotal = 'total'; const kFileExtension = "file_extension"; + +const kEvently = "Evently";