diff --git a/lib/widgets/custom_buttons/paynym_follow_toggle_button.dart b/lib/widgets/custom_buttons/paynym_follow_toggle_button.dart new file mode 100644 index 000000000..3ac4db4b3 --- /dev/null +++ b/lib/widgets/custom_buttons/paynym_follow_toggle_button.dart @@ -0,0 +1,255 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:stackwallet/models/paynym/paynym_account_lite.dart'; +import 'package:stackwallet/models/paynym/paynym_response.dart'; +import 'package:stackwallet/notifications/show_flush_bar.dart'; +import 'package:stackwallet/providers/global/paynym_api_provider.dart'; +import 'package:stackwallet/providers/global/wallets_provider.dart'; +import 'package:stackwallet/providers/wallet/my_paynym_account_state_provider.dart'; +import 'package:stackwallet/services/coins/coin_paynym_extension.dart'; +import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart'; +import 'package:stackwallet/utilities/util.dart'; +import 'package:stackwallet/widgets/desktop/primary_button.dart'; +import 'package:stackwallet/widgets/loading_indicator.dart'; + +class PaynymFollowToggleButton extends ConsumerStatefulWidget { + const PaynymFollowToggleButton({ + Key? key, + required this.walletId, + required this.paymentCodeStringToFollow, + }) : super(key: key); + + final String walletId; + final String paymentCodeStringToFollow; + + @override + ConsumerState createState() => + _PaynymFollowToggleButtonState(); +} + +class _PaynymFollowToggleButtonState + extends ConsumerState { + final isDesktop = Util.isDesktop; + + Future follow() async { + bool loadingPopped = false; + unawaited( + showDialog( + context: context, + builder: (context) => const LoadingIndicator( + width: 200, + ), + ).then( + (_) => loadingPopped = true, + ), + ); + + final wallet = ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .wallet as DogecoinWallet; + + final followedAccount = await ref + .read(paynymAPIProvider) + .nym(widget.paymentCodeStringToFollow, true); + + final myPCode = await wallet.getPaymentCode(); + + PaynymResponse token = + await ref.read(paynymAPIProvider).token(myPCode.toString()); + + // sign token with notification private key + String signature = await wallet.signStringWithNotificationKey(token.value!); + + var result = await ref.read(paynymAPIProvider).follow( + token.value!, signature, followedAccount.value!.codes.first.code); + + int i = 0; + for (; + i < 10 && + result.statusCode == 401; //"401 Unauthorized - Bad signature"; + i++) { + token = await ref.read(paynymAPIProvider).token(myPCode.toString()); + + // sign token with notification private key + signature = await wallet.signStringWithNotificationKey(token.value!); + + result = await ref.read(paynymAPIProvider).follow( + token.value!, signature, followedAccount.value!.codes.first.code); + await Future.delayed(const Duration(milliseconds: 200)); + + print("RRR result: $result"); + } + + print("Follow result: $result on try $i"); + + if (result.value!.following == followedAccount.value!.nymID) { + if (!loadingPopped && mounted) { + Navigator.of(context).pop(); + } + + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "You are following ${followedAccount.value!.nymName}", + context: context, + ), + ); + ref.read(myPaynymAccountStateProvider.state).state!.following.add( + PaynymAccountLite( + followedAccount.value!.nymID, + followedAccount.value!.nymName, + followedAccount.value!.codes.first.code, + followedAccount.value!.codes.first.segwit, + ), + ); + + setState(() { + isFollowing = true; + }); + + return true; + } else { + if (!loadingPopped && mounted) { + Navigator.of(context).pop(); + } + + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Failed to follow ${followedAccount.value!.nymName}", + context: context, + ), + ); + + return false; + } + } + + Future unfollow() async { + bool loadingPopped = false; + unawaited( + showDialog( + context: context, + builder: (context) => const LoadingIndicator( + width: 200, + ), + ).then( + (_) => loadingPopped = true, + ), + ); + + final wallet = ref + .read(walletsChangeNotifierProvider) + .getManager(widget.walletId) + .wallet as DogecoinWallet; + + final followedAccount = await ref + .read(paynymAPIProvider) + .nym(widget.paymentCodeStringToFollow, true); + + final myPCode = await wallet.getPaymentCode(); + + PaynymResponse token = + await ref.read(paynymAPIProvider).token(myPCode.toString()); + + // sign token with notification private key + String signature = await wallet.signStringWithNotificationKey(token.value!); + + var result = await ref.read(paynymAPIProvider).unfollow( + token.value!, signature, followedAccount.value!.codes.first.code); + + int i = 0; + for (; + i < 10 && + result.statusCode == 401; //"401 Unauthorized - Bad signature"; + i++) { + token = await ref.read(paynymAPIProvider).token(myPCode.toString()); + + // sign token with notification private key + signature = await wallet.signStringWithNotificationKey(token.value!); + + result = await ref.read(paynymAPIProvider).unfollow( + token.value!, signature, followedAccount.value!.codes.first.code); + await Future.delayed(const Duration(milliseconds: 200)); + print("unfollow RRR result: $result"); + } + + print("Unfollow result: $result on try $i"); + + if (result.value!.unfollowing == followedAccount.value!.nymID) { + if (!loadingPopped && mounted) { + Navigator.of(context).pop(); + } + + unawaited( + showFloatingFlushBar( + type: FlushBarType.success, + message: "You have unfollowed ${followedAccount.value!.nymName}", + context: context, + ), + ); + ref + .read(myPaynymAccountStateProvider.state) + .state! + .following + .removeWhere((e) => e.nymId == followedAccount.value!.nymID); + + setState(() { + isFollowing = false; + }); + + return true; + } else { + if (!loadingPopped && mounted) { + Navigator.of(context).pop(); + } + + unawaited( + showFloatingFlushBar( + type: FlushBarType.warning, + message: "Failed to unfollow ${followedAccount.value!.nymName}", + context: context, + ), + ); + + return false; + } + } + + bool _lock = false; + late bool isFollowing; + + @override + void initState() { + isFollowing = ref + .read(myPaynymAccountStateProvider.state) + .state! + .following + .where((e) => e.code == widget.paymentCodeStringToFollow) + .isNotEmpty; + super.initState(); + } + + @override + Widget build(BuildContext context) { + return PrimaryButton( + width: isDesktop ? 120 : 84, + buttonHeight: ButtonHeight.l, + label: isFollowing ? "Unfollow" : "Follow", + onPressed: () async { + if (!_lock) { + _lock = true; + if (isFollowing) { + await unfollow(); + } else { + await follow(); + } + _lock = false; + } + }, + ); + } +}