mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 20:09:23 +00:00
WIP follow/unfollow
This commit is contained in:
parent
0711bd03cf
commit
7631d3f3c6
11 changed files with 377 additions and 77 deletions
|
@ -1,6 +1,6 @@
|
||||||
class CreatedPaynym {
|
class CreatedPaynym {
|
||||||
final bool claimed;
|
final bool claimed;
|
||||||
final String nymAvatar;
|
final String? nymAvatar;
|
||||||
final String? nymId;
|
final String? nymId;
|
||||||
final String? nymName;
|
final String? nymName;
|
||||||
final String? token;
|
final String? token;
|
||||||
|
@ -15,8 +15,8 @@ class CreatedPaynym {
|
||||||
|
|
||||||
CreatedPaynym.fromMap(Map<String, dynamic> map)
|
CreatedPaynym.fromMap(Map<String, dynamic> map)
|
||||||
: claimed = map["claimed"] as bool,
|
: claimed = map["claimed"] as bool,
|
||||||
nymAvatar = map["nymAvatar"] as String,
|
nymAvatar = map["nymAvatar"] as String?,
|
||||||
nymId = map["nymId"] as String?,
|
nymId = map["nymID"] as String?,
|
||||||
nymName = map["nymName"] as String?,
|
nymName = map["nymName"] as String?,
|
||||||
token = map["token"] as String?;
|
token = map["token"] as String?;
|
||||||
|
|
||||||
|
|
|
@ -26,19 +26,27 @@ class PaynymAccount {
|
||||||
codes = (map["codes"] as List<dynamic>)
|
codes = (map["codes"] as List<dynamic>)
|
||||||
.map((e) => PaynymCode.fromMap(Map<String, dynamic>.from(e as Map)))
|
.map((e) => PaynymCode.fromMap(Map<String, dynamic>.from(e as Map)))
|
||||||
.toList(),
|
.toList(),
|
||||||
followers = (map["followers"] as List<dynamic>)
|
followers = [],
|
||||||
.map((e) => e["nymId"] as String)
|
following = [] {
|
||||||
.toList(),
|
final f1 = map["followers"] as List<dynamic>;
|
||||||
following = (map["following"] as List<dynamic>)
|
for (final item in f1) {
|
||||||
.map((e) => e["nymId"] as String)
|
followers.add(Map<String, dynamic>.from(item as Map)["nymId"] as String);
|
||||||
.toList();
|
}
|
||||||
|
|
||||||
|
final f2 = map["following"] as List<dynamic>;
|
||||||
|
for (final item in f2) {
|
||||||
|
final nymId = Map<String, dynamic>.from(item as Map)["nymId"] as String;
|
||||||
|
print(nymId + "DDDDDDDDDDDDD");
|
||||||
|
following.add(nymId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toMap() => {
|
Map<String, dynamic> toMap() => {
|
||||||
"nymID": nymID,
|
"nymID": nymID,
|
||||||
"nymName": nymName,
|
"nymName": nymName,
|
||||||
"codes": codes.map((e) => e.toMap()),
|
"codes": codes.map((e) => e.toMap()),
|
||||||
"followers": followers.map((e) => {"nymId": e}),
|
"followers": followers.map((e) => {"nymId": e}).toList(),
|
||||||
"following": followers.map((e) => {"nymId": e}),
|
"following": followers.map((e) => {"nymId": e}).toList(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -28,11 +28,9 @@ class AddNewPaynymFollowView extends ConsumerStatefulWidget {
|
||||||
const AddNewPaynymFollowView({
|
const AddNewPaynymFollowView({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.walletId,
|
required this.walletId,
|
||||||
required this.nymAccount,
|
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String walletId;
|
final String walletId;
|
||||||
final PaynymAccount nymAccount;
|
|
||||||
|
|
||||||
static const String routeName = "/addNewPaynymFollow";
|
static const String routeName = "/addNewPaynymFollow";
|
||||||
|
|
||||||
|
@ -64,8 +62,7 @@ class _AddNewPaynymFollowViewState
|
||||||
).then((_) => didPopLoading = true),
|
).then((_) => didPopLoading = true),
|
||||||
);
|
);
|
||||||
|
|
||||||
final paynymAccount =
|
final paynymAccount = await ref.read(paynymAPIProvider).nym(_searchString);
|
||||||
await ref.read(paynymAPIProvider).nym(_searchString, true);
|
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
if (!didPopLoading) {
|
if (!didPopLoading) {
|
||||||
|
@ -143,7 +140,9 @@ class _AddNewPaynymFollowViewState
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 12,
|
height: 12,
|
||||||
),
|
),
|
||||||
const FeaturedPaynymsWidget(),
|
FeaturedPaynymsWidget(
|
||||||
|
walletId: widget.walletId,
|
||||||
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
|
@ -295,6 +294,7 @@ class _AddNewPaynymFollowViewState
|
||||||
child: PaynymCard(
|
child: PaynymCard(
|
||||||
label: _searchResult!.nymName,
|
label: _searchResult!.nymName,
|
||||||
paymentCodeString: _searchResult!.codes.first.code,
|
paymentCodeString: _searchResult!.codes.first.code,
|
||||||
|
walletId: widget.walletId,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages/paynym/dialogs/claiming_paynym_dialog.dart';
|
import 'package:stackwallet/pages/paynym/dialogs/claiming_paynym_dialog.dart';
|
||||||
|
import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
|
||||||
|
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||||
import 'package:stackwallet/providers/global/paynym_api_provider.dart';
|
import 'package:stackwallet/providers/global/paynym_api_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
import 'package:stackwallet/services/coins/coin_paynym_extension.dart';
|
import 'package:stackwallet/services/coins/coin_paynym_extension.dart';
|
||||||
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
||||||
import 'package:stackwallet/utilities/assets.dart';
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
import 'package:stackwallet/utilities/format.dart';
|
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:stackwallet/utilities/util.dart';
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
@ -106,39 +106,50 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
|
||||||
.read(paynymAPIProvider)
|
.read(paynymAPIProvider)
|
||||||
.create(pCode.toString());
|
.create(pCode.toString());
|
||||||
|
|
||||||
|
debugPrint("created:$created");
|
||||||
|
|
||||||
if (created.claimed) {
|
if (created.claimed) {
|
||||||
// payment code already claimed
|
// payment code already claimed
|
||||||
debugPrint("pcode already claimed!!");
|
debugPrint("pcode already claimed!!");
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context).popUntil(
|
||||||
|
ModalRoute.withName(
|
||||||
|
WalletView.routeName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String token;
|
final token =
|
||||||
|
await ref.read(paynymAPIProvider).token(pCode.toString());
|
||||||
if (created.token == null) {
|
|
||||||
// payment code already in db
|
|
||||||
// so we need to fetch a token
|
|
||||||
|
|
||||||
token = await ref
|
|
||||||
.read(paynymAPIProvider)
|
|
||||||
.token(pCode.toString());
|
|
||||||
} else {
|
|
||||||
token = created.token!;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sign token with notification private key
|
// sign token with notification private key
|
||||||
final signatureBytes = await wallet.signWithNotificationKey(
|
final signature =
|
||||||
Uint8List.fromList(token.codeUnits));
|
await wallet.signStringWithNotificationKey(token);
|
||||||
final signature = Format.uint8listToString(signatureBytes);
|
|
||||||
|
|
||||||
// claim paynym account
|
// claim paynym account
|
||||||
final claim =
|
final claim =
|
||||||
await ref.read(paynymAPIProvider).claim(token, signature);
|
await ref.read(paynymAPIProvider).claim(token, signature);
|
||||||
|
|
||||||
if (claim["claimed"] == pCode.toString()) {
|
if (claim["claimed"] == pCode.toString()) {
|
||||||
// mark claim successful
|
final account =
|
||||||
}
|
await ref.read(paynymAPIProvider).nym(pCode.toString());
|
||||||
|
|
||||||
if (mounted && !shouldCancel) {
|
ref.read(myPaynymAccountStateProvider.state).state =
|
||||||
|
account!;
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context).popUntil(
|
||||||
|
ModalRoute.withName(
|
||||||
|
WalletView.routeName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
PaynymHomeView.routeName,
|
||||||
|
arguments: widget.walletId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (mounted && !shouldCancel) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:stackwallet/models/paynym/paynym_account.dart';
|
import 'package:stackwallet/models/paynym/paynym_account.dart';
|
||||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
|
@ -22,26 +23,35 @@ import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
|
||||||
import 'package:stackwallet/widgets/icon_widgets/share_icon.dart';
|
import 'package:stackwallet/widgets/icon_widgets/share_icon.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
import 'package:stackwallet/widgets/toggle.dart';
|
import 'package:stackwallet/widgets/toggle.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
|
||||||
|
|
||||||
class PaynymHomeView extends StatefulWidget {
|
final myPaynymAccountStateProvider =
|
||||||
|
StateProvider<PaynymAccount?>((ref) => null);
|
||||||
|
|
||||||
|
class PaynymHomeView extends ConsumerStatefulWidget {
|
||||||
const PaynymHomeView({
|
const PaynymHomeView({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.walletId,
|
required this.walletId,
|
||||||
required this.paynymAccount,
|
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String walletId;
|
final String walletId;
|
||||||
final PaynymAccount paynymAccount;
|
|
||||||
|
|
||||||
static const String routeName = "/paynymHome";
|
static const String routeName = "/paynymHome";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<PaynymHomeView> createState() => _PaynymHomeViewState();
|
ConsumerState<PaynymHomeView> createState() => _PaynymHomeViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PaynymHomeViewState extends State<PaynymHomeView> {
|
class _PaynymHomeViewState extends ConsumerState<PaynymHomeView> {
|
||||||
bool showFollowing = false;
|
bool showFollowing = false;
|
||||||
|
int secretCount = 0;
|
||||||
|
Timer? timer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
timer?.cancel();
|
||||||
|
timer = null;
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -77,10 +87,7 @@ class _PaynymHomeViewState extends State<PaynymHomeView> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pushNamed(
|
Navigator.of(context).pushNamed(
|
||||||
AddNewPaynymFollowView.routeName,
|
AddNewPaynymFollowView.routeName,
|
||||||
arguments: Tuple2(
|
arguments: widget.walletId,
|
||||||
widget.walletId,
|
|
||||||
widget.paynymAccount,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -114,21 +121,54 @@ class _PaynymHomeViewState extends State<PaynymHomeView> {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
PayNymBot(
|
GestureDetector(
|
||||||
paymentCodeString: widget.paynymAccount.codes.first.code,
|
onTap: () {
|
||||||
|
secretCount++;
|
||||||
|
if (secretCount > 5) {
|
||||||
|
debugPrint(
|
||||||
|
"My Account: ${ref.read(myPaynymAccountStateProvider.state).state}");
|
||||||
|
debugPrint(
|
||||||
|
"My Account: ${ref.read(myPaynymAccountStateProvider.state).state!.following}");
|
||||||
|
secretCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer ??= Timer(
|
||||||
|
const Duration(milliseconds: 1500),
|
||||||
|
() {
|
||||||
|
secretCount = 0;
|
||||||
|
timer = null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: PayNymBot(
|
||||||
|
paymentCodeString: ref
|
||||||
|
.watch(myPaynymAccountStateProvider.state)
|
||||||
|
.state!
|
||||||
|
.codes
|
||||||
|
.first
|
||||||
|
.code,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
widget.paynymAccount.nymName,
|
ref.watch(myPaynymAccountStateProvider.state).state!.nymName,
|
||||||
style: STextStyles.desktopMenuItemSelected(context),
|
style: STextStyles.desktopMenuItemSelected(context),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 4,
|
height: 4,
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
Format.shorten(widget.paynymAccount.codes.first.code, 12, 5),
|
Format.shorten(
|
||||||
|
ref
|
||||||
|
.watch(myPaynymAccountStateProvider.state)
|
||||||
|
.state!
|
||||||
|
.codes
|
||||||
|
.first
|
||||||
|
.code,
|
||||||
|
12,
|
||||||
|
5),
|
||||||
style: STextStyles.label(context),
|
style: STextStyles.label(context),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
|
@ -151,7 +191,12 @@ class _PaynymHomeViewState extends State<PaynymHomeView> {
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await Clipboard.setData(
|
await Clipboard.setData(
|
||||||
ClipboardData(
|
ClipboardData(
|
||||||
text: widget.paynymAccount.codes.first.code,
|
text: ref
|
||||||
|
.read(myPaynymAccountStateProvider.state)
|
||||||
|
.state!
|
||||||
|
.codes
|
||||||
|
.first
|
||||||
|
.code,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
unawaited(
|
unawaited(
|
||||||
|
@ -204,7 +249,9 @@ class _PaynymHomeViewState extends State<PaynymHomeView> {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => PaynymQrPopup(
|
builder: (context) => PaynymQrPopup(
|
||||||
paynymAccount: widget.paynymAccount,
|
paynymAccount: ref
|
||||||
|
.read(myPaynymAccountStateProvider.state)
|
||||||
|
.state!,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,12 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
class FeaturedPaynymsWidget extends StatelessWidget {
|
class FeaturedPaynymsWidget extends StatelessWidget {
|
||||||
const FeaturedPaynymsWidget({Key? key}) : super(key: key);
|
const FeaturedPaynymsWidget({
|
||||||
|
Key? key,
|
||||||
|
required this.walletId,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final String walletId;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -26,6 +31,7 @@ class FeaturedPaynymsWidget extends StatelessWidget {
|
||||||
height: 1,
|
height: 1,
|
||||||
),
|
),
|
||||||
PaynymCard(
|
PaynymCard(
|
||||||
|
walletId: walletId,
|
||||||
label: entries[i].key,
|
label: entries[i].key,
|
||||||
paymentCodeString: entries[i].value,
|
paymentCodeString: entries[i].value,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,17 +1,29 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
|
import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
|
||||||
import 'package:stackwallet/pages/paynym/subwidgets/paynym_bot.dart';
|
import 'package:stackwallet/pages/paynym/subwidgets/paynym_bot.dart';
|
||||||
|
import 'package:stackwallet/providers/global/paynym_api_provider.dart';
|
||||||
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
|
import 'package:stackwallet/services/coins/coin_paynym_extension.dart';
|
||||||
|
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
||||||
import 'package:stackwallet/utilities/format.dart';
|
import 'package:stackwallet/utilities/format.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
|
|
||||||
class PaynymCard extends StatefulWidget {
|
class PaynymCard extends StatefulWidget {
|
||||||
const PaynymCard({
|
const PaynymCard({
|
||||||
Key? key,
|
Key? key,
|
||||||
|
required this.walletId,
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.paymentCodeString,
|
required this.paymentCodeString,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final String walletId;
|
||||||
final String label;
|
final String label;
|
||||||
final String paymentCodeString;
|
final String paymentCodeString;
|
||||||
|
|
||||||
|
@ -55,16 +67,225 @@ class _PaynymCardState extends State<PaynymCard> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
PrimaryButton(
|
PaynymFollowToggleButton(
|
||||||
width: 84,
|
walletId: widget.walletId,
|
||||||
buttonHeight: ButtonHeight.l,
|
paymentCodeStringToFollow: widget.paymentCodeString,
|
||||||
label: "Follow",
|
),
|
||||||
onPressed: () {
|
// PrimaryButton(
|
||||||
// todo : follow
|
// width: 84,
|
||||||
},
|
// buttonHeight: ButtonHeight.l,
|
||||||
)
|
// label: "Follow",
|
||||||
|
// onPressed: () {
|
||||||
|
// // todo : follow
|
||||||
|
// },
|
||||||
|
// )
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<PaynymFollowToggleButton> createState() =>
|
||||||
|
_PaynymFollowToggleButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PaynymFollowToggleButtonState
|
||||||
|
extends ConsumerState<PaynymFollowToggleButton> {
|
||||||
|
Future<bool> follow() async {
|
||||||
|
bool loadingPopped = false;
|
||||||
|
unawaited(
|
||||||
|
showDialog<void>(
|
||||||
|
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);
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
|
||||||
|
final myPCode = await wallet.getPaymentCode();
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
final token = await ref.read(paynymAPIProvider).token(myPCode.toString());
|
||||||
|
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
|
||||||
|
// sign token with notification private key
|
||||||
|
final signature = await wallet.signStringWithNotificationKey(token);
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
|
||||||
|
final result = await ref
|
||||||
|
.read(paynymAPIProvider)
|
||||||
|
.follow(token, signature, followedAccount!.codes.first.code);
|
||||||
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
|
|
||||||
|
print("Follow result: $result");
|
||||||
|
|
||||||
|
if (result["following"] == followedAccount.nymID) {
|
||||||
|
if (!loadingPopped && mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
unawaited(
|
||||||
|
showFloatingFlushBar(
|
||||||
|
type: FlushBarType.success,
|
||||||
|
message: "You are following ${followedAccount.nymName}",
|
||||||
|
context: context,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
ref
|
||||||
|
.read(myPaynymAccountStateProvider.state)
|
||||||
|
.state!
|
||||||
|
.following
|
||||||
|
.add(followedAccount.codes.first.code);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
isFollowing = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (!loadingPopped && mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
unawaited(
|
||||||
|
showFloatingFlushBar(
|
||||||
|
type: FlushBarType.warning,
|
||||||
|
message: "Failed to follow ${followedAccount.nymName}",
|
||||||
|
context: context,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> unfollow() async {
|
||||||
|
bool loadingPopped = false;
|
||||||
|
unawaited(
|
||||||
|
showDialog<void>(
|
||||||
|
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();
|
||||||
|
final token = await ref.read(paynymAPIProvider).token(myPCode.toString());
|
||||||
|
|
||||||
|
// sign token with notification private key
|
||||||
|
final signature = await wallet.signStringWithNotificationKey(token);
|
||||||
|
|
||||||
|
final result = await ref
|
||||||
|
.read(paynymAPIProvider)
|
||||||
|
.unfollow(token, signature, followedAccount!.codes.first.code);
|
||||||
|
|
||||||
|
print("Unfollow result: $result");
|
||||||
|
|
||||||
|
if (result["unfollowing"] == followedAccount.nymID) {
|
||||||
|
if (!loadingPopped && mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
unawaited(
|
||||||
|
showFloatingFlushBar(
|
||||||
|
type: FlushBarType.success,
|
||||||
|
message: "You have unfollowed ${followedAccount.nymName}",
|
||||||
|
context: context,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
ref
|
||||||
|
.read(myPaynymAccountStateProvider.state)
|
||||||
|
.state!
|
||||||
|
.following
|
||||||
|
.remove(followedAccount.codes.first.code);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
isFollowing = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (!loadingPopped && mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
unawaited(
|
||||||
|
showFloatingFlushBar(
|
||||||
|
type: FlushBarType.warning,
|
||||||
|
message: "Failed to unfollow ${followedAccount.nymName}",
|
||||||
|
context: context,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _lock = false;
|
||||||
|
late bool isFollowing;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
isFollowing = ref
|
||||||
|
.read(myPaynymAccountStateProvider.state)
|
||||||
|
.state!
|
||||||
|
.following
|
||||||
|
.contains(widget.paymentCodeStringToFollow);
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return PrimaryButton(
|
||||||
|
width: 84,
|
||||||
|
buttonHeight: ButtonHeight.l,
|
||||||
|
label: isFollowing ? "Unfollow" : "Follow",
|
||||||
|
onPressed: () async {
|
||||||
|
if (!_lock) {
|
||||||
|
_lock = true;
|
||||||
|
if (isFollowing) {
|
||||||
|
await unfollow();
|
||||||
|
} else {
|
||||||
|
await follow();
|
||||||
|
}
|
||||||
|
_lock = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,9 +13,7 @@ import 'package:stackwallet/utilities/assets.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
|
|
||||||
import '../../../widgets/loading_indicator.dart';
|
|
||||||
|
|
||||||
class WalletNavigationBar extends StatefulWidget {
|
class WalletNavigationBar extends StatefulWidget {
|
||||||
const WalletNavigationBar({
|
const WalletNavigationBar({
|
||||||
|
@ -135,12 +133,12 @@ class _WalletNavigationBarState extends State<WalletNavigationBar> {
|
||||||
.where((e) =>
|
.where((e) =>
|
||||||
e.code == code.toString() && e.claimed)
|
e.code == code.toString() && e.claimed)
|
||||||
.isNotEmpty) {
|
.isNotEmpty) {
|
||||||
|
ref.read(myPaynymAccountStateProvider.state).state =
|
||||||
|
account;
|
||||||
|
|
||||||
await Navigator.of(context).pushNamed(
|
await Navigator.of(context).pushNamed(
|
||||||
PaynymHomeView.routeName,
|
PaynymHomeView.routeName,
|
||||||
arguments: Tuple2(
|
arguments: widget.walletId,
|
||||||
widget.walletId,
|
|
||||||
account,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await Navigator.of(context).pushNamed(
|
await Navigator.of(context).pushNamed(
|
||||||
|
|
|
@ -6,7 +6,6 @@ import 'package:stackwallet/models/contact_address_entry.dart';
|
||||||
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
import 'package:stackwallet/models/exchange/incomplete_exchange.dart';
|
||||||
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
|
||||||
import 'package:stackwallet/models/paymint/transactions_model.dart';
|
import 'package:stackwallet/models/paymint/transactions_model.dart';
|
||||||
import 'package:stackwallet/models/paynym/paynym_account.dart';
|
|
||||||
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
|
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart';
|
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/add_wallet_view.dart';
|
||||||
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart';
|
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart';
|
||||||
|
@ -206,12 +205,11 @@ class RouteGenerator {
|
||||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||||
|
|
||||||
case PaynymHomeView.routeName:
|
case PaynymHomeView.routeName:
|
||||||
if (args is Tuple2<String, PaynymAccount>) {
|
if (args is String) {
|
||||||
return getRoute(
|
return getRoute(
|
||||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
builder: (_) => PaynymHomeView(
|
builder: (_) => PaynymHomeView(
|
||||||
walletId: args.item1,
|
walletId: args,
|
||||||
paynymAccount: args.item2,
|
|
||||||
),
|
),
|
||||||
settings: RouteSettings(
|
settings: RouteSettings(
|
||||||
name: settings.name,
|
name: settings.name,
|
||||||
|
@ -221,12 +219,11 @@ class RouteGenerator {
|
||||||
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
return _routeError("${settings.name} invalid args: ${args.toString()}");
|
||||||
|
|
||||||
case AddNewPaynymFollowView.routeName:
|
case AddNewPaynymFollowView.routeName:
|
||||||
if (args is Tuple2<String, PaynymAccount>) {
|
if (args is String) {
|
||||||
return getRoute(
|
return getRoute(
|
||||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
builder: (_) => AddNewPaynymFollowView(
|
builder: (_) => AddNewPaynymFollowView(
|
||||||
walletId: args.item1,
|
walletId: args,
|
||||||
nymAccount: args.item2,
|
|
||||||
),
|
),
|
||||||
settings: RouteSettings(
|
settings: RouteSettings(
|
||||||
name: settings.name,
|
name: settings.name,
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:bitcoindart/bitcoindart.dart';
|
||||||
import 'package:pointycastle/digests/sha256.dart';
|
import 'package:pointycastle/digests/sha256.dart';
|
||||||
import 'package:stackwallet/hive/db.dart';
|
import 'package:stackwallet/hive/db.dart';
|
||||||
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
import 'package:stackwallet/services/coins/dogecoin/dogecoin_wallet.dart';
|
||||||
|
import 'package:stackwallet/utilities/format.dart';
|
||||||
|
|
||||||
extension PayNym on DogecoinWallet {
|
extension PayNym on DogecoinWallet {
|
||||||
// fetch or generate this wallet's bip47 payment code
|
// fetch or generate this wallet's bip47 payment code
|
||||||
|
@ -35,6 +36,15 @@ extension PayNym on DogecoinWallet {
|
||||||
return signed;
|
return signed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<String> signStringWithNotificationKey(String data) async {
|
||||||
|
final bytes =
|
||||||
|
await signWithNotificationKey(Uint8List.fromList(data.codeUnits));
|
||||||
|
return Format.uint8listToString(bytes);
|
||||||
|
// final bytes =
|
||||||
|
// await signWithNotificationKey(Uint8List.fromList(utf8.encode(data)));
|
||||||
|
// return Format.uint8listToString(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
// Future<Map<String, dynamic>> prepareNotificationTransaction(
|
// Future<Map<String, dynamic>> prepareNotificationTransaction(
|
||||||
// String targetPaymentCode) async {}
|
// String targetPaymentCode) async {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ class PrimaryButton extends StatelessWidget {
|
||||||
this.onPressed,
|
this.onPressed,
|
||||||
this.enabled = true,
|
this.enabled = true,
|
||||||
this.buttonHeight,
|
this.buttonHeight,
|
||||||
|
this.iconSpacing = 10,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final double? width;
|
final double? width;
|
||||||
|
@ -25,6 +26,7 @@ class PrimaryButton extends StatelessWidget {
|
||||||
final bool enabled;
|
final bool enabled;
|
||||||
final Widget? icon;
|
final Widget? icon;
|
||||||
final ButtonHeight? buttonHeight;
|
final ButtonHeight? buttonHeight;
|
||||||
|
final double? iconSpacing;
|
||||||
|
|
||||||
TextStyle getStyle(bool isDesktop, BuildContext context) {
|
TextStyle getStyle(bool isDesktop, BuildContext context) {
|
||||||
if (isDesktop) {
|
if (isDesktop) {
|
||||||
|
@ -143,8 +145,8 @@ class PrimaryButton extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
if (icon != null) icon!,
|
if (icon != null) icon!,
|
||||||
if (icon != null && label != null)
|
if (icon != null && label != null)
|
||||||
const SizedBox(
|
SizedBox(
|
||||||
width: 10,
|
width: iconSpacing,
|
||||||
),
|
),
|
||||||
if (label != null)
|
if (label != null)
|
||||||
Text(
|
Text(
|
||||||
|
|
Loading…
Reference in a new issue