mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-03 17:29:23 +00:00
WIP paynym home view
This commit is contained in:
parent
a491bfd70f
commit
3b6d53d685
16 changed files with 521 additions and 134 deletions
3
assets/svg/circle-plus-filled.svg
Normal file
3
assets/svg/circle-plus-filled.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 10C0 4.47656 4.47656 0 10 0C15.5234 0 20 4.47656 20 10C20 15.5234 15.5234 20 10 20C4.47656 20 0 15.5234 0 10ZM10 14.375C10.5195 14.375 10.9375 13.957 10.9375 13.4375V10.9375H13.4375C13.957 10.9375 14.375 10.5195 14.375 10C14.375 9.48047 13.957 9.0625 13.4375 9.0625H10.9375V6.5625C10.9375 6.04297 10.5195 5.625 10 5.625C9.48047 5.625 9.0625 6.04297 9.0625 6.5625V9.0625H6.5625C6.04297 9.0625 5.625 9.48047 5.625 10C5.625 10.5195 6.04297 10.9375 6.5625 10.9375H9.0625V13.4375C9.0625 13.957 9.48047 14.375 10 14.375Z" fill="#232323"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 648 B |
48
lib/models/paynym/paynym_account.dart
Normal file
48
lib/models/paynym/paynym_account.dart
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import 'package:stackwallet/models/paynym/paynym_code.dart';
|
||||||
|
|
||||||
|
class PaynymAccount {
|
||||||
|
final String nymID;
|
||||||
|
final String nymName;
|
||||||
|
|
||||||
|
final List<PaynymCode> codes;
|
||||||
|
|
||||||
|
/// list of nymId
|
||||||
|
final List<String> followers;
|
||||||
|
|
||||||
|
/// list of nymId
|
||||||
|
final List<String> following;
|
||||||
|
|
||||||
|
PaynymAccount(
|
||||||
|
this.nymID,
|
||||||
|
this.nymName,
|
||||||
|
this.codes,
|
||||||
|
this.followers,
|
||||||
|
this.following,
|
||||||
|
);
|
||||||
|
|
||||||
|
PaynymAccount.fromMap(Map<String, dynamic> map)
|
||||||
|
: nymID = map["nymID"] as String,
|
||||||
|
nymName = map["nymName"] as String,
|
||||||
|
codes = (map["codes"] as List<dynamic>)
|
||||||
|
.map((e) => PaynymCode.fromMap(Map<String, dynamic>.from(e as Map)))
|
||||||
|
.toList(),
|
||||||
|
followers = (map["followers"] as List<dynamic>)
|
||||||
|
.map((e) => e["nymId"] as String)
|
||||||
|
.toList(),
|
||||||
|
following = (map["following"] as List<dynamic>)
|
||||||
|
.map((e) => e["nymId"] as String)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() => {
|
||||||
|
"nymID": nymID,
|
||||||
|
"nymName": nymName,
|
||||||
|
"codes": codes.map((e) => e.toMap()),
|
||||||
|
"followers": followers.map((e) => {"nymId": e}),
|
||||||
|
"following": followers.map((e) => {"nymId": e}),
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return toMap().toString();
|
||||||
|
}
|
||||||
|
}
|
27
lib/models/paynym/paynym_code.dart
Normal file
27
lib/models/paynym/paynym_code.dart
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
class PaynymCode {
|
||||||
|
final bool claimed;
|
||||||
|
final bool segwit;
|
||||||
|
final String code;
|
||||||
|
|
||||||
|
PaynymCode(
|
||||||
|
this.claimed,
|
||||||
|
this.segwit,
|
||||||
|
this.code,
|
||||||
|
);
|
||||||
|
|
||||||
|
PaynymCode.fromMap(Map<String, dynamic> map)
|
||||||
|
: claimed = map["claimed"] as bool,
|
||||||
|
segwit = map["segwit"] as bool,
|
||||||
|
code = map["code"] as String;
|
||||||
|
|
||||||
|
Map<String, dynamic> toMap() => {
|
||||||
|
"claimed": claimed,
|
||||||
|
"segwit": segwit,
|
||||||
|
"code": code,
|
||||||
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return toMap().toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
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';
|
||||||
|
@ -8,6 +9,7 @@ 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';
|
||||||
|
@ -88,53 +90,52 @@ class _PaynymClaimViewState extends ConsumerState<PaynymClaimView> {
|
||||||
builder: (context) => const ClaimingPaynymDialog(),
|
builder: (context) => const ClaimingPaynymDialog(),
|
||||||
).then((value) => shouldCancel = value == true),
|
).then((value) => shouldCancel = value == true),
|
||||||
);
|
);
|
||||||
// generate and submit paynym to api
|
|
||||||
|
|
||||||
|
// ghet wallet to access paynym calls
|
||||||
final wallet = ref
|
final wallet = ref
|
||||||
.read(walletsChangeNotifierProvider)
|
.read(walletsChangeNotifierProvider)
|
||||||
.getManager(widget.walletId)
|
.getManager(widget.walletId)
|
||||||
.wallet as DogecoinWallet;
|
.wallet as DogecoinWallet;
|
||||||
|
|
||||||
|
// get payment code
|
||||||
final pCode = await wallet.getPaymentCode();
|
final pCode = await wallet.getPaymentCode();
|
||||||
|
|
||||||
final result = await ref
|
// attempt to create new entry in paynym.is db
|
||||||
|
final created = await ref
|
||||||
.read(paynymAPIProvider)
|
.read(paynymAPIProvider)
|
||||||
.create(pCode.toString());
|
.create(pCode.toString());
|
||||||
|
|
||||||
// final result =
|
if (created.claimed) {
|
||||||
// await ref.read(paynymAPIProvider).token(pCode.toString());
|
// payment code already claimed
|
||||||
|
debugPrint("pcode already claimed!!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// final token =
|
String token;
|
||||||
// "IlBNOFRKWWt1U2RZWEpud0RCcThDaGZpbmZYdjNzcnhoUXJ4M2VvRXdiU3c1MXdNamRvOUpKMkRzeWN3VDNndDN6SFE3Y1YxZ3J2YWJNbW1mMUJ0ajZmWTd0Z2tnU3o5QjhNWnVSM2tqWWZnTUxNVVJKQ1hOIg.FoPF3g.KUMZDC4U_ek-B6cqPLYilXniQv8";
|
|
||||||
//
|
|
||||||
// print("======================");
|
|
||||||
// print(token);
|
|
||||||
// print(token.codeUnits);
|
|
||||||
// print(utf8.encode(token));
|
|
||||||
// print(utf8.decode(token.codeUnits));
|
|
||||||
//
|
|
||||||
// print("======================");
|
|
||||||
//
|
|
||||||
// final signed = await wallet.signWithNotificationKey(
|
|
||||||
// Uint8List.fromList(token.codeUnits));
|
|
||||||
//
|
|
||||||
// final signedString = Format.uint8listToString(signed);
|
|
||||||
//
|
|
||||||
// print("======================");
|
|
||||||
// print(signed);
|
|
||||||
// print(signedString);
|
|
||||||
//
|
|
||||||
// print("======================");
|
|
||||||
|
|
||||||
// final result2 = await ref
|
if (created.token == null) {
|
||||||
// .read(paynymAPIProvider)
|
// payment code already in db
|
||||||
// .claim(token, signedString);
|
// so we need to fetch a token
|
||||||
|
|
||||||
// print("======================");
|
token = await ref
|
||||||
// print(
|
.read(paynymAPIProvider)
|
||||||
// result2); // {claimed: PM8TJYkuSdYXJnwDBq8ChfinfXv3srxhQrx3eoEwbSw51wMjdo9JJ2DsycwT3gt3zHQ7cV1grvabMmmf1Btj6fY7tgkgSz9B8MZuR3kjYfgMLMURJCXN, token: IlBNOFRKWWt1U2RZWEpud0RCcThDaGZpbmZYdjNzcnhoUXJ4M2VvRXdiU3c1MXdNamRvOUpKMkRzeWN3VDNndDN6SFE3Y1YxZ3J2YWJNbW1mMUJ0ajZmWTd0Z2tnU3o5QjhNWnVSM2tqWWZnTUxNVVJKQ1hOIg.FoPF3g.KUMZDC4U_ek-B6cqPLYilXniQv8}
|
.token(pCode.toString());
|
||||||
// print("======================");
|
} else {
|
||||||
|
token = created.token!;
|
||||||
|
}
|
||||||
|
|
||||||
await Future<void>.delayed(const Duration(seconds: 3));
|
// sign token with notification private key
|
||||||
|
final signatureBytes = await wallet.signWithNotificationKey(
|
||||||
|
Uint8List.fromList(token.codeUnits));
|
||||||
|
final signature = Format.uint8listToString(signatureBytes);
|
||||||
|
|
||||||
|
// claim paynym account
|
||||||
|
final claim =
|
||||||
|
await ref.read(paynymAPIProvider).claim(token, signature);
|
||||||
|
|
||||||
|
if (claim["claimed"] == pCode.toString()) {
|
||||||
|
// mark claim successful
|
||||||
|
}
|
||||||
|
|
||||||
if (mounted && !shouldCancel) {
|
if (mounted && !shouldCancel) {
|
||||||
Navigator.of(context).pop();
|
Navigator.of(context).pop();
|
||||||
|
|
|
@ -1,18 +1,31 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:stackwallet/models/paynym/paynym_account.dart';
|
||||||
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
|
import 'package:stackwallet/utilities/constants.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/util.dart';
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/copy_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/icon_widgets/share_icon.dart';
|
||||||
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
import 'package:stackwallet/widgets/toggle.dart';
|
||||||
|
|
||||||
class PaynymHomeView extends StatefulWidget {
|
class PaynymHomeView extends StatefulWidget {
|
||||||
const PaynymHomeView({
|
const PaynymHomeView({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.walletId,
|
required this.walletId,
|
||||||
required this.paymentCodeString,
|
required this.nymAccount,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String walletId;
|
final String walletId;
|
||||||
final String paymentCodeString;
|
final PaynymAccount nymAccount;
|
||||||
|
|
||||||
static const String routeName = "/paynymHome";
|
static const String routeName = "/paynymHome";
|
||||||
|
|
||||||
|
@ -21,6 +34,8 @@ class PaynymHomeView extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _PaynymHomeViewState extends State<PaynymHomeView> {
|
class _PaynymHomeViewState extends State<PaynymHomeView> {
|
||||||
|
bool showFollowing = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
debugPrint("BUILD: $runtimeType");
|
debugPrint("BUILD: $runtimeType");
|
||||||
|
@ -40,14 +55,172 @@ class _PaynymHomeViewState extends State<PaynymHomeView> {
|
||||||
style: STextStyles.navBarTitle(context),
|
style: STextStyles.navBarTitle(context),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
|
actions: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: AppBarIconButton(
|
||||||
|
icon: SvgPicture.asset(
|
||||||
|
Assets.svg.circlePlusFilled,
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
color: Theme.of(context).extension<StackColors>()!.textDark,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// todo add ?
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 6),
|
||||||
|
child: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: AppBarIconButton(
|
||||||
|
icon: SvgPicture.asset(
|
||||||
|
Assets.svg.circleQuestion,
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
color: Theme.of(context).extension<StackColors>()!.textDark,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// todo add ?
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 4,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
PayNymBot(
|
PayNymBot(
|
||||||
paymentCodeString: widget.paymentCodeString,
|
paymentCodeString: widget.nymAccount.codes.first.code,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
widget.nymAccount.nymName,
|
||||||
|
style: STextStyles.desktopMenuItemSelected(context),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 4,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
Format.shorten(widget.nymAccount.codes.first.code, 12, 5),
|
||||||
|
style: STextStyles.label(context),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 11,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: SecondaryButton(
|
||||||
|
label: "Copy",
|
||||||
|
buttonHeight: ButtonHeight.l,
|
||||||
|
iconSpacing: 4,
|
||||||
|
icon: CopyIcon(
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textDark,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// copy to clipboard
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 13,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: SecondaryButton(
|
||||||
|
label: "Share",
|
||||||
|
buttonHeight: ButtonHeight.l,
|
||||||
|
iconSpacing: 4,
|
||||||
|
icon: ShareIcon(
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textDark,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// copy to clipboard
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 13,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: SecondaryButton(
|
||||||
|
label: "Address",
|
||||||
|
buttonHeight: ButtonHeight.l,
|
||||||
|
iconSpacing: 4,
|
||||||
|
icon: QrCodeIcon(
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textDark,
|
||||||
|
),
|
||||||
|
onPressed: () {
|
||||||
|
// copy to clipboard
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: Toggle(
|
||||||
|
onColor: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
onText: "Following",
|
||||||
|
offColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textFieldDefaultBG,
|
||||||
|
offText: "Followers",
|
||||||
|
isOn: showFollowing,
|
||||||
|
onValueChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
showFollowing = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.blue,
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Your PayNym contacts will appear here",
|
||||||
|
style: STextStyles.label(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -61,12 +234,30 @@ class PayNymBot extends StatelessWidget {
|
||||||
const PayNymBot({
|
const PayNymBot({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.paymentCodeString,
|
required this.paymentCodeString,
|
||||||
|
this.size = 60.0,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String paymentCodeString;
|
final String paymentCodeString;
|
||||||
|
final double size;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Image.network("https://paynym.is/$paymentCodeString/avatar");
|
return ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(size / 2),
|
||||||
|
child: SizedBox(
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
child: Image.network(
|
||||||
|
"https://paynym.is/$paymentCodeString/avatar",
|
||||||
|
loadingBuilder: (context, child, event) {
|
||||||
|
if (event == null) {
|
||||||
|
return child;
|
||||||
|
} else {
|
||||||
|
return const LoadingIndicator();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
|
import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
|
||||||
|
import 'package:stackwallet/pages/paynym/paynym_home_view.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/assets.dart';
|
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 '../../../widgets/loading_indicator.dart';
|
||||||
|
|
||||||
class WalletNavigationBar extends StatefulWidget {
|
class WalletNavigationBar extends StatefulWidget {
|
||||||
const WalletNavigationBar({
|
const WalletNavigationBar({
|
||||||
|
@ -88,42 +99,84 @@ class _WalletNavigationBarState extends State<WalletNavigationBar> {
|
||||||
AnimatedOpacity(
|
AnimatedOpacity(
|
||||||
opacity: scale,
|
opacity: scale,
|
||||||
duration: duration,
|
duration: duration,
|
||||||
child: GestureDetector(
|
child: Consumer(builder: (context, ref, __) {
|
||||||
onTap: () {
|
return GestureDetector(
|
||||||
setState(() {
|
onTap: () async {
|
||||||
scale = 0;
|
setState(() {
|
||||||
});
|
scale = 0;
|
||||||
Navigator.of(context).pushNamed(
|
});
|
||||||
PaynymClaimView.routeName,
|
unawaited(
|
||||||
arguments: widget.walletId,
|
showDialog(
|
||||||
);
|
context: context,
|
||||||
},
|
builder: (context) => const LoadingIndicator(
|
||||||
child: Container(
|
width: 100,
|
||||||
padding: const EdgeInsets.all(16),
|
),
|
||||||
width: 146,
|
),
|
||||||
decoration: BoxDecoration(
|
);
|
||||||
color:
|
|
||||||
Theme.of(context).extension<StackColors>()!.popupBG,
|
// todo make generic and not doge specific
|
||||||
boxShadow: [
|
final wallet = (ref
|
||||||
Theme.of(context)
|
.read(walletsChangeNotifierProvider)
|
||||||
.extension<StackColors>()!
|
.getManager(widget.walletId)
|
||||||
.standardBoxShadow
|
.wallet as DogecoinWallet);
|
||||||
],
|
|
||||||
borderRadius: BorderRadius.circular(
|
final code = await wallet.getPaymentCode();
|
||||||
widget.height / 2.0,
|
|
||||||
|
final account = await ref
|
||||||
|
.read(paynymAPIProvider)
|
||||||
|
.nym(code.toString());
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
|
||||||
|
// check if account exists and for matching code to see if claimed
|
||||||
|
if (account != null &&
|
||||||
|
account.codes
|
||||||
|
.where((e) =>
|
||||||
|
e.code == code.toString() && e.claimed)
|
||||||
|
.isNotEmpty) {
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
PaynymHomeView.routeName,
|
||||||
|
arguments: Tuple2(
|
||||||
|
widget.walletId,
|
||||||
|
account,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await Navigator.of(context).pushNamed(
|
||||||
|
PaynymClaimView.routeName,
|
||||||
|
arguments: widget.walletId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
width: 146,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
boxShadow: [
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.standardBoxShadow
|
||||||
|
],
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
widget.height / 2.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Paynym",
|
||||||
|
style: STextStyles.w600_12(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
);
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
}),
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Paynym",
|
|
||||||
style: STextStyles.w600_12(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 8,
|
height: 8,
|
||||||
|
|
|
@ -6,6 +6,7 @@ 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';
|
||||||
|
@ -204,12 +205,12 @@ 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, String>) {
|
if (args is Tuple2<String, PaynymAccount>) {
|
||||||
return getRoute(
|
return getRoute(
|
||||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||||
builder: (_) => PaynymHomeView(
|
builder: (_) => PaynymHomeView(
|
||||||
walletId: args.item1,
|
walletId: args.item1,
|
||||||
paymentCodeString: args.item2,
|
nymAccount: args.item2,
|
||||||
),
|
),
|
||||||
settings: RouteSettings(
|
settings: RouteSettings(
|
||||||
name: settings.name,
|
name: settings.name,
|
||||||
|
|
|
@ -34,4 +34,7 @@ extension PayNym on DogecoinWallet {
|
||||||
final signed = pair.sign(SHA256Digest().process(data));
|
final signed = pair.sign(SHA256Digest().process(data));
|
||||||
return signed;
|
return signed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Future<Map<String, dynamic>> prepareNotificationTransaction(
|
||||||
|
// String targetPaymentCode) async {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ class _SVG {
|
||||||
|
|
||||||
String get circleSliders => "assets/svg/configuration.svg";
|
String get circleSliders => "assets/svg/configuration.svg";
|
||||||
String get circlePlus => "assets/svg/plus-circle.svg";
|
String get circlePlus => "assets/svg/plus-circle.svg";
|
||||||
|
String get circlePlusFilled => "assets/svg/circle-plus-filled.svg";
|
||||||
String get framedGear => "assets/svg/framed-gear.svg";
|
String get framedGear => "assets/svg/framed-gear.svg";
|
||||||
String get framedAddressBook => "assets/svg/framed-address-book.svg";
|
String get framedAddressBook => "assets/svg/framed-address-book.svg";
|
||||||
String get circleNode => "assets/svg/node-circle.svg";
|
String get circleNode => "assets/svg/node-circle.svg";
|
||||||
|
|
|
@ -8,6 +8,10 @@ import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
|
||||||
abstract class Format {
|
abstract class Format {
|
||||||
|
static String shorten(String value, int beginCount, int endCount) {
|
||||||
|
return "${value.substring(0, beginCount)}...${value.substring(value.length - endCount)}";
|
||||||
|
}
|
||||||
|
|
||||||
static Decimal satoshisToAmount(int sats, {required Coin coin}) {
|
static Decimal satoshisToAmount(int sats, {required Coin coin}) {
|
||||||
return (Decimal.fromInt(sats) /
|
return (Decimal.fromInt(sats) /
|
||||||
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
Decimal.fromInt(Constants.satsPerCoin(coin)))
|
||||||
|
|
|
@ -2,6 +2,7 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'package:stackwallet/models/paynym/created_paynym.dart';
|
import 'package:stackwallet/models/paynym/created_paynym.dart';
|
||||||
|
import 'package:stackwallet/models/paynym/paynym_account.dart';
|
||||||
|
|
||||||
class PaynymAPI {
|
class PaynymAPI {
|
||||||
static const String baseURL = "https://paynym.is/api";
|
static const String baseURL = "https://paynym.is/api";
|
||||||
|
@ -117,8 +118,9 @@ class PaynymAPI {
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// ------
|
// ------
|
||||||
Future<Map<String, dynamic>> token(String code) async {
|
Future<String> token(String code) async {
|
||||||
return _post("/token", {"code": code});
|
final map = await _post("/token", {"code": code});
|
||||||
|
return map["token"] as String;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ### `/api/v1/nym`
|
// ### `/api/v1/nym`
|
||||||
|
@ -172,8 +174,13 @@ class PaynymAPI {
|
||||||
// | 404 | Nym not found |
|
// | 404 | Nym not found |
|
||||||
// | 400 | Bad request |
|
// | 400 | Bad request |
|
||||||
|
|
||||||
Future<Map<String, dynamic>> nym(String code) async {
|
Future<PaynymAccount?> nym(String code) async {
|
||||||
return _post("/nym", {"code": code});
|
final map = await _post("/nym", {"nym": code});
|
||||||
|
try {
|
||||||
|
return PaynymAccount.fromMap(map);
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ## Authenticated Requests
|
// ## Authenticated Requests
|
||||||
|
|
|
@ -16,6 +16,7 @@ class SecondaryButton 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 SecondaryButton 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) {
|
||||||
|
@ -66,6 +68,16 @@ class SecondaryButton extends StatelessWidget {
|
||||||
: STextStyles.desktopButtonSecondaryDisabled(context);
|
: STextStyles.desktopButtonSecondaryDisabled(context);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (buttonHeight == ButtonHeight.l) {
|
||||||
|
return STextStyles.button(context).copyWith(
|
||||||
|
fontSize: 10,
|
||||||
|
color: enabled
|
||||||
|
? Theme.of(context).extension<StackColors>()!.buttonTextSecondary
|
||||||
|
: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.buttonTextSecondaryDisabled,
|
||||||
|
);
|
||||||
|
}
|
||||||
return STextStyles.button(context).copyWith(
|
return STextStyles.button(context).copyWith(
|
||||||
color: enabled
|
color: enabled
|
||||||
? Theme.of(context).extension<StackColors>()!.buttonTextSecondary
|
? Theme.of(context).extension<StackColors>()!.buttonTextSecondary
|
||||||
|
@ -136,8 +148,8 @@ class SecondaryButton 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(
|
||||||
|
|
27
lib/widgets/icon_widgets/share_icon.dart
Normal file
27
lib/widgets/icon_widgets/share_icon.dart
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||||
|
|
||||||
|
class ShareIcon extends StatelessWidget {
|
||||||
|
const ShareIcon({
|
||||||
|
Key? key,
|
||||||
|
this.width = 18,
|
||||||
|
this.height = 18,
|
||||||
|
this.color,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final double width;
|
||||||
|
final double height;
|
||||||
|
final Color? color;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return SvgPicture.asset(
|
||||||
|
Assets.svg.share,
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
color: color ?? Theme.of(context).extension<StackColors>()!.textDark3,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lottie/lottie.dart';
|
import 'package:lottie/lottie.dart';
|
||||||
|
|
||||||
import 'package:stackwallet/utilities/assets.dart';
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
|
|
||||||
class LoadingIndicator extends StatelessWidget {
|
class LoadingIndicator extends StatelessWidget {
|
||||||
|
@ -15,13 +14,18 @@ class LoadingIndicator extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return Container(
|
||||||
width: width,
|
color: Colors.transparent,
|
||||||
height: height,
|
child: Center(
|
||||||
child: Lottie.asset(
|
child: SizedBox(
|
||||||
Assets.lottie.test2,
|
width: width,
|
||||||
animate: true,
|
height: height,
|
||||||
repeat: true,
|
child: Lottie.asset(
|
||||||
|
Assets.lottie.test2,
|
||||||
|
animate: true,
|
||||||
|
repeat: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,29 +186,31 @@ class ToggleState extends State<Toggle> {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
SvgPicture.asset(
|
if (widget.onIcon != null)
|
||||||
widget.onIcon ?? "",
|
SvgPicture.asset(
|
||||||
width: 12,
|
widget.onIcon ?? "",
|
||||||
height: 14,
|
width: 12,
|
||||||
color: isDesktop
|
height: 14,
|
||||||
? !_isOn
|
color: isDesktop
|
||||||
? Theme.of(context)
|
? !_isOn
|
||||||
.extension<StackColors>()!
|
? Theme.of(context)
|
||||||
.accentColorBlue
|
.extension<StackColors>()!
|
||||||
: Theme.of(context)
|
.accentColorBlue
|
||||||
.extension<StackColors>()!
|
: Theme.of(context)
|
||||||
.buttonTextSecondary
|
.extension<StackColors>()!
|
||||||
: !_isOn
|
.buttonTextSecondary
|
||||||
? Theme.of(context)
|
: !_isOn
|
||||||
.extension<StackColors>()!
|
? Theme.of(context)
|
||||||
.textDark
|
.extension<StackColors>()!
|
||||||
: Theme.of(context)
|
.textDark
|
||||||
.extension<StackColors>()!
|
: Theme.of(context)
|
||||||
.textSubtitle1,
|
.extension<StackColors>()!
|
||||||
),
|
.textSubtitle1,
|
||||||
const SizedBox(
|
),
|
||||||
width: 5,
|
if (widget.onIcon != null)
|
||||||
),
|
const SizedBox(
|
||||||
|
width: 5,
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
widget.onText ?? "",
|
widget.onText ?? "",
|
||||||
style: isDesktop
|
style: isDesktop
|
||||||
|
@ -243,29 +245,31 @@ class ToggleState extends State<Toggle> {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
SvgPicture.asset(
|
if (widget.offIcon != null)
|
||||||
widget.offIcon ?? "",
|
SvgPicture.asset(
|
||||||
width: 12,
|
widget.offIcon ?? "",
|
||||||
height: 14,
|
width: 12,
|
||||||
color: isDesktop
|
height: 14,
|
||||||
? _isOn
|
color: isDesktop
|
||||||
? Theme.of(context)
|
? _isOn
|
||||||
.extension<StackColors>()!
|
? Theme.of(context)
|
||||||
.accentColorBlue
|
.extension<StackColors>()!
|
||||||
: Theme.of(context)
|
.accentColorBlue
|
||||||
.extension<StackColors>()!
|
: Theme.of(context)
|
||||||
.buttonTextSecondary
|
.extension<StackColors>()!
|
||||||
: _isOn
|
.buttonTextSecondary
|
||||||
? Theme.of(context)
|
: _isOn
|
||||||
.extension<StackColors>()!
|
? Theme.of(context)
|
||||||
.textDark
|
.extension<StackColors>()!
|
||||||
: Theme.of(context)
|
.textDark
|
||||||
.extension<StackColors>()!
|
: Theme.of(context)
|
||||||
.textSubtitle1,
|
.extension<StackColors>()!
|
||||||
),
|
.textSubtitle1,
|
||||||
const SizedBox(
|
),
|
||||||
width: 5,
|
if (widget.offIcon != null)
|
||||||
),
|
const SizedBox(
|
||||||
|
width: 5,
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
widget.offText ?? "",
|
widget.offText ?? "",
|
||||||
style: isDesktop
|
style: isDesktop
|
||||||
|
|
|
@ -305,6 +305,7 @@ flutter:
|
||||||
- assets/svg/keys.svg
|
- assets/svg/keys.svg
|
||||||
- assets/svg/arrow-down.svg
|
- assets/svg/arrow-down.svg
|
||||||
- assets/svg/plus-circle.svg
|
- assets/svg/plus-circle.svg
|
||||||
|
- assets/svg/circle-plus-filled.svg
|
||||||
- assets/svg/configuration.svg
|
- assets/svg/configuration.svg
|
||||||
# coin icons
|
# coin icons
|
||||||
- assets/svg/coin_icons/Bitcoin.svg
|
- assets/svg/coin_icons/Bitcoin.svg
|
||||||
|
|
Loading…
Reference in a new issue