WIP paynym home view

This commit is contained in:
julian 2022-12-21 10:17:53 -06:00
parent a491bfd70f
commit 3b6d53d685
16 changed files with 521 additions and 134 deletions

View 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

View 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();
}
}

View 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();
}
}

View file

@ -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();

View file

@ -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();
}
},
),
),
);
} }
} }

View file

@ -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,

View file

@ -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,

View file

@ -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 {}
} }

View file

@ -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";

View file

@ -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)))

View file

@ -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

View file

@ -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(

View 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,
);
}
}

View file

@ -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,
),
),
), ),
); );
} }

View file

@ -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

View file

@ -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