From a43b97026a8511628b3167c6f4e29c36d0cf893c Mon Sep 17 00:00:00 2001 From: vishnukvmd Date: Wed, 21 Aug 2024 17:39:23 +0530 Subject: [PATCH] Add option to claim a custom referral code --- mobile/lib/gateways/storage_bonus_gw.dart | 9 +++ mobile/lib/generated/intl/messages_en.dart | 9 ++- mobile/lib/generated/l10n.dart | 44 +++++++++- mobile/lib/l10n/intl_en.arb | 4 + .../lib/ui/growth/referral_code_widget.dart | 81 +++++++++++++++++-- mobile/lib/ui/growth/referral_screen.dart | 78 +++++++++++------- 6 files changed, 185 insertions(+), 40 deletions(-) diff --git a/mobile/lib/gateways/storage_bonus_gw.dart b/mobile/lib/gateways/storage_bonus_gw.dart index 5b6aad24e5..3b6a08641b 100644 --- a/mobile/lib/gateways/storage_bonus_gw.dart +++ b/mobile/lib/gateways/storage_bonus_gw.dart @@ -15,6 +15,15 @@ class StorageBonusGateway { return _enteDio.post("/storage-bonus/referral-claim?code=$code"); } + Future updateCode(String code) { + return _enteDio.post( + "/storage-bonus/change-code?code=$code", + data: { + "code": code, + }, + ); + } + Future getBonusDetails() async { final response = await _enteDio.get("/storage-bonus/details"); return BonusDetails.fromJson(response.data); diff --git a/mobile/lib/generated/intl/messages_en.dart b/mobile/lib/generated/intl/messages_en.dart index d7d288c542..c0dda0ce55 100644 --- a/mobile/lib/generated/intl/messages_en.dart +++ b/mobile/lib/generated/intl/messages_en.dart @@ -413,6 +413,7 @@ class MessageLookup extends MessageLookupByLibrary { "castInstruction": MessageLookupByLibrary.simpleMessage( "Visit cast.ente.io on the device you want to pair.\n\nEnter the code below to play the album on your TV."), "centerPoint": MessageLookupByLibrary.simpleMessage("Center point"), + "change": MessageLookupByLibrary.simpleMessage("Change"), "changeEmail": MessageLookupByLibrary.simpleMessage("Change email"), "changeLocationOfSelectedItems": MessageLookupByLibrary.simpleMessage( "Change location of selected items?"), @@ -422,6 +423,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Change password"), "changePermissions": MessageLookupByLibrary.simpleMessage("Change permissions?"), + "changeYourReferralCode": + MessageLookupByLibrary.simpleMessage("Change your referral code"), "checkForUpdates": MessageLookupByLibrary.simpleMessage("Check for updates"), "checkInboxAndSpamFolder": MessageLookupByLibrary.simpleMessage( @@ -431,7 +434,7 @@ class MessageLookup extends MessageLookupByLibrary { "cl_guest_view_call_to_action": MessageLookupByLibrary.simpleMessage( "Select photos and check out \"Guest view\"."), "cl_guest_view_description": MessageLookupByLibrary.simpleMessage( - "Handing over your phone to show photos to a friend? Don\'t worry about them swiping too far.\nGuest view will lock them into the photos you select."), + "Handing over your phone to show photos to a friend? Don\'t worry about them swiping too far. Guest view will lock them into the photos you select."), "cl_guest_view_title": MessageLookupByLibrary.simpleMessage("Guest View"), "cl_panorama_viewer_description": MessageLookupByLibrary.simpleMessage( @@ -465,6 +468,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Clustering progress"), "codeAppliedPageTitle": MessageLookupByLibrary.simpleMessage("Code applied"), + "codeChangeLimitReached": MessageLookupByLibrary.simpleMessage( + "Sorry, you\'ve reached the limit of code changes."), "codeCopiedToClipboard": MessageLookupByLibrary.simpleMessage("Code copied to clipboard"), "codeUsedByYou": @@ -1573,6 +1578,8 @@ class MessageLookup extends MessageLookupByLibrary { "unarchiveAlbum": MessageLookupByLibrary.simpleMessage("Unarchive album"), "unarchiving": MessageLookupByLibrary.simpleMessage("Unarchiving..."), + "unavailableReferralCode": MessageLookupByLibrary.simpleMessage( + "Sorry, this code is unavailable."), "uncategorized": MessageLookupByLibrary.simpleMessage("Uncategorized"), "unhide": MessageLookupByLibrary.simpleMessage("Unhide"), "unhideToAlbum": diff --git a/mobile/lib/generated/l10n.dart b/mobile/lib/generated/l10n.dart index 51b8974d54..a1ad4fe581 100644 --- a/mobile/lib/generated/l10n.dart +++ b/mobile/lib/generated/l10n.dart @@ -2056,6 +2056,46 @@ class S { ); } + /// `Change your referral code` + String get changeYourReferralCode { + return Intl.message( + 'Change your referral code', + name: 'changeYourReferralCode', + desc: '', + args: [], + ); + } + + /// `Change` + String get change { + return Intl.message( + 'Change', + name: 'change', + desc: '', + args: [], + ); + } + + /// `Sorry, this code is unavailable.` + String get unavailableReferralCode { + return Intl.message( + 'Sorry, this code is unavailable.', + name: 'unavailableReferralCode', + desc: '', + args: [], + ); + } + + /// `Sorry, you've reached the limit of code changes.` + String get codeChangeLimitReached { + return Intl.message( + 'Sorry, you\'ve reached the limit of code changes.', + name: 'codeChangeLimitReached', + desc: '', + args: [], + ); + } + /// `{storageAmountInGB} GB` String storageInGB(Object storageAmountInGB) { return Intl.message( @@ -9375,10 +9415,10 @@ class S { ); } - /// `Handing over your phone to show photos to a friend? Don't worry about them swiping too far.\nGuest view will lock them into the photos you select.` + /// `Handing over your phone to show photos to a friend? Don't worry about them swiping too far. Guest view will lock them into the photos you select.` String get cl_guest_view_description { return Intl.message( - 'Handing over your phone to show photos to a friend? Don\'t worry about them swiping too far.\nGuest view will lock them into the photos you select.', + 'Handing over your phone to show photos to a friend? Don\'t worry about them swiping too far. Guest view will lock them into the photos you select.', name: 'cl_guest_view_description', desc: '', args: [], diff --git a/mobile/lib/l10n/intl_en.arb b/mobile/lib/l10n/intl_en.arb index 61b3c67f05..6c6deb74d9 100644 --- a/mobile/lib/l10n/intl_en.arb +++ b/mobile/lib/l10n/intl_en.arb @@ -273,6 +273,10 @@ "failedToApplyCode": "Failed to apply code", "enterReferralCode": "Enter referral code", "codeAppliedPageTitle": "Code applied", + "changeYourReferralCode": "Change your referral code", + "change": "Change", + "unavailableReferralCode": "Sorry, this code is unavailable.", + "codeChangeLimitReached": "Sorry, you've reached the limit of code changes.", "storageInGB": "{storageAmountInGB} GB", "claimed": "Claimed", "@claimed": { diff --git a/mobile/lib/ui/growth/referral_code_widget.dart b/mobile/lib/ui/growth/referral_code_widget.dart index 910ef8de09..d22e591c4d 100644 --- a/mobile/lib/ui/growth/referral_code_widget.dart +++ b/mobile/lib/ui/growth/referral_code_widget.dart @@ -1,12 +1,24 @@ +import "package:dio/dio.dart"; import "package:dotted_border/dotted_border.dart"; import "package:flutter/material.dart"; +import "package:logging/logging.dart"; +import "package:photos/generated/l10n.dart"; +import "package:photos/services/storage_bonus_service.dart"; import "package:photos/theme/ente_theme.dart"; +import "package:photos/utils/dialog_util.dart"; // Figma: https://www.figma.com/file/SYtMyLBs5SAOkTbfMMzhqt/ente-Visual-Design?node-id=11219%3A62974&t=BRCLJhxXP11Q3Wyw-0 class ReferralCodeWidget extends StatelessWidget { final String codeValue; + final bool shouldAllowEdit; + final Function? notifyParent; - const ReferralCodeWidget(this.codeValue, {Key? key}) : super(key: key); + const ReferralCodeWidget( + this.codeValue, { + this.shouldAllowEdit = false, + this.notifyParent, + super.key, + }); @override Widget build(BuildContext context) { @@ -37,11 +49,18 @@ class ReferralCodeWidget extends StatelessWidget { ), ), const SizedBox(width: 12), - Icon( - Icons.adaptive.share, - size: 22, - color: colorScheme.strokeMuted, - ), + shouldAllowEdit + ? GestureDetector( + onTap: () { + showUpdateReferralCodeDialog(context); + }, + child: Icon( + Icons.edit, + size: 22, + color: colorScheme.strokeMuted, + ), + ) + : const SizedBox.shrink(), ], ), ), @@ -49,4 +68,54 @@ class ReferralCodeWidget extends StatelessWidget { ), ); } + + Future showUpdateReferralCodeDialog(BuildContext context) async { + final result = await showTextInputDialog( + context, + title: S.of(context).changeYourReferralCode, + submitButtonLabel: S.of(context).change, + hintText: S.of(context).enterCode, + alwaysShowSuccessState: true, + initialValue: codeValue, + textCapitalization: TextCapitalization.characters, + onSubmit: (String text) async { + // indicates user cancelled the request + if (text == "" || text.trim() == codeValue) { + return; + } + + try { + await StorageBonusService.instance + .getGateway() + .updateCode(text.trim().toUpperCase()); + notifyParent?.call(); + } catch (e, s) { + Logger("ReferralCodeWidget").severe("Failed to update code", e, s); + if (e is DioError) { + if (e.response?.statusCode == 400) { + await showInfoDialog( + context, + title: S.of(context).error, + body: S.of(context).unavailableReferralCode, + icon: Icons.error, + ); + return; + } else if (e.response?.statusCode == 429) { + await showInfoDialog( + context, + title: S.of(context).error, + body: S.of(context).codeChangeLimitReached, + icon: Icons.error, + ); + return; + } + } + rethrow; + } + }, + ); + if (result is Exception) { + await showGenericErrorDialog(context: context, error: result); + } + } } diff --git a/mobile/lib/ui/growth/referral_screen.dart b/mobile/lib/ui/growth/referral_screen.dart index 570114600d..521f9bccf6 100644 --- a/mobile/lib/ui/growth/referral_screen.dart +++ b/mobile/lib/ui/growth/referral_screen.dart @@ -141,41 +141,57 @@ class ReferralWidget extends StatelessWidget { ), ); }, - child: Container( - width: double.infinity, - decoration: BoxDecoration( - border: Border.all( - color: colorScheme.strokeFaint, - width: 1, - ), - borderRadius: BorderRadius.circular(8), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12, - horizontal: 12, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - S.of(context).referralStep1, + child: Stack( + children: [ + Container( + width: double.infinity, + decoration: BoxDecoration( + border: Border.all( + color: colorScheme.strokeFaint, + width: 1, ), - const SizedBox(height: 12), - ReferralCodeWidget(referralView.code), - const SizedBox(height: 12), - Text( - S.of(context).referralStep2, + borderRadius: BorderRadius.circular(8), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 12, ), - const SizedBox(height: 12), - Text( - S - .of(context) - .referralStep3(referralView.planInfo.storageInGB), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + S.of(context).referralStep1, + ), + const SizedBox(height: 12), + ReferralCodeWidget( + referralView.code, + shouldAllowEdit: true, + notifyParent: notifyParent, + ), + const SizedBox(height: 12), + Text( + S.of(context).referralStep2, + ), + const SizedBox(height: 12), + Text( + S.of(context).referralStep3( + referralView.planInfo.storageInGB, + ), + ), + ], ), - ], + ), ), - ), + Positioned( + right: 8, + top: 8, + child: Icon( + Icons.adaptive.share, + color: colorScheme.blurStrokePressed, + ), + ), + ], ), ) : Padding(