CAKE-360 | merged all yat branches into current; saving information about yat to connected wallet; fixed qr widget; applied yat, unstoppable domains and open alias to contact book

This commit is contained in:
OleksandrSobol 2021-10-01 18:13:10 +03:00
parent 5389543988
commit f353442a2a
26 changed files with 789 additions and 113 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -62,7 +62,7 @@ import 'package:cake_wallet/src/screens/send/send_page.dart';
import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.dart';
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
import 'package:cake_wallet/store/wallet_list_store.dart';
import 'package:cake_wallet/store/yat_store.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cake_wallet/view_model/backup_view_model.dart';
import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
import 'package:cake_wallet/view_model/buy/buy_view_model.dart';
@ -193,7 +193,9 @@ Future setup(
SendTemplateStore(templateSource: _templates));
getIt.registerSingleton<ExchangeTemplateStore>(
ExchangeTemplateStore(templateSource: _exchangeTemplates));
getIt.registerSingleton<YatStore>(YatStore());
getIt.registerSingleton<YatStore>(YatStore(
appStore: getIt.get<AppStore>()
));
final secretStore =
await SecretStoreBase.load(getIt.get<FlutterSecureStorage>());
@ -254,6 +256,7 @@ Future setup(
tradeFilterStore: getIt.get<TradeFilterStore>(),
transactionFilterStore: getIt.get<TransactionFilterStore>(),
settingsStore: settingsStore,
yatStore: getIt.get<YatStore>(),
ordersStore: getIt.get<OrdersStore>()));
getIt.registerFactory<AuthService>(() => AuthService(
@ -391,7 +394,8 @@ Future setup(
getIt.registerFactory(() {
final appStore = getIt.get<AppStore>();
return SettingsViewModel(appStore.settingsStore, appStore.wallet);
final yatStore = getIt.get<YatStore>();
return SettingsViewModel(appStore.settingsStore, yatStore, appStore.wallet);
});
getIt.registerFactory(() => SettingsPage(getIt.get<SettingsViewModel>()));

View file

@ -1,7 +1,7 @@
import 'package:cake_wallet/entities/openalias_record.dart';
import 'package:cake_wallet/entities/parsed_address.dart';
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
import 'package:cake_wallet/yat/yat_record.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
const unstoppableDomains = [
'crypto',

View file

@ -7,7 +7,8 @@ part 'wallet_info.g.dart';
@HiveType(typeId: WalletInfo.typeId)
class WalletInfo extends HiveObject {
WalletInfo(this.id, this.name, this.type, this.isRecovery, this.restoreHeight,
this.timestamp, this.dirPath, this.path, this.address);
this.timestamp, this.dirPath, this.path, this.address, this.yatEid,
this.yatRefreshToken);
factory WalletInfo.external(
{@required String id,
@ -18,9 +19,12 @@ class WalletInfo extends HiveObject {
@required DateTime date,
@required String dirPath,
@required String path,
@required String address}) {
@required String address,
String yatEid ='',
String yatRefreshToken = ''}) {
return WalletInfo(id, name, type, isRecovery, restoreHeight,
date.millisecondsSinceEpoch ?? 0, dirPath, path, address);
date.millisecondsSinceEpoch ?? 0, dirPath, path, address,
yatEid, yatRefreshToken);
}
static const typeId = 4;
@ -56,5 +60,15 @@ class WalletInfo extends HiveObject {
@HiveField(10)
Map<String, String> addresses;
@HiveField(11)
String yatEid;
@HiveField(12)
String yatRefreshToken;
String get yatEmojiId => yatEid ?? '';
String get yatToken => yatRefreshToken ?? '';
DateTime get date => DateTime.fromMillisecondsSinceEpoch(timestamp);
}

View file

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:cake_wallet/bitcoin/unspent_coins_info.dart';
import 'package:cake_wallet/entities/language_service.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/store/yat_store.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -190,8 +190,8 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
_handleIncomingLinks(yatStore);
_handleInitialUri(yatStore);
_handleIncomingLinks();
_handleInitialUri();
}
@override
@ -200,25 +200,25 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
super.dispose();
}
Future<void> _handleInitialUri(YatStore yatStore) async {
Future<void> _handleInitialUri() async {
try {
final uri = await getInitialUri();
if (uri == null) {
return;
}
if (!mounted) return;
_fetchEmojiFromUri(uri, yatStore);
_fetchEmojiFromUri(uri);
} catch (e) {
if (!mounted) return;
print(e.toString());
}
}
void _handleIncomingLinks(YatStore yatStore) {
void _handleIncomingLinks() {
if (!kIsWeb) {
stream = getUriLinksStream().listen((Uri uri) {
if (!mounted) return;
_fetchEmojiFromUri(uri, yatStore);
_fetchEmojiFromUri(uri);
}, onError: (Object error) {
if (!mounted) return;
print('Error: $error');
@ -226,16 +226,18 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
}
}
void _fetchEmojiFromUri(Uri uri, YatStore yatStore) {
void _fetchEmojiFromUri(Uri uri) {
final queryParameters = uri.queryParameters;
if (queryParameters?.isEmpty ?? true) {
return;
}
final emoji = queryParameters['eid'];
if (emoji?.isEmpty ?? true) {
final refreshToken = queryParameters['refresh_token'];
if ((emoji?.isEmpty ?? true)||(refreshToken?.isEmpty ?? true)) {
return;
}
yatStore.emoji = emoji;
yatStore.refreshToken = refreshToken;
}
@override

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
@ -97,8 +98,9 @@ class ContactPage extends BasePage {
buttonColor: Theme.of(context).accentTextTheme.display2.color,
iconColor: PaletteDark.gray,
borderColor: Theme.of(context).primaryTextTheme.title.backgroundColor,
validator: AddressValidator(
type: contactViewModel.currency),
validator: TextValidator()
// AddressValidator(
// type: contactViewModel.currency),
)),
)
],

View file

@ -1,6 +1,7 @@
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/yat/yat_popup.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
@ -145,7 +146,7 @@ class DashboardPage extends BasePage {
));
}
void _setEffects(BuildContext context) {
void _setEffects(BuildContext context) async {
if (_isEffectsInstalled) {
return;
}
@ -155,6 +156,15 @@ class DashboardPage extends BasePage {
pages.add(BalancePage(dashboardViewModel: walletViewModel));
pages.add(TransactionsPage(dashboardViewModel: walletViewModel));
await Future<void>.delayed(Duration(seconds: 1));
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return YatPopup(
dashboardViewModel: walletViewModel,
onClose: () => Navigator.of(context).pop());
});
autorun((_) async {
if (!walletViewModel.isOutdatedElectrumWallet) {
return;

View file

@ -235,6 +235,15 @@ class ExchangePage extends BasePage {
await fetchParsedAddress(
context, domain, ticker);
},
onPushAddressBookButton: (context) async {
final domain =
exchangeViewModel.depositAddress;
final ticker = exchangeViewModel
.depositCurrency.title.toLowerCase();
exchangeViewModel.depositAddress =
await fetchParsedAddress(
context, domain, ticker);
},
),
),
),
@ -291,6 +300,15 @@ class ExchangePage extends BasePage {
await fetchParsedAddress(
context, domain, ticker);
},
onPushAddressBookButton: (context) async {
final domain =
exchangeViewModel.receiveAddress;
final ticker = exchangeViewModel
.receiveCurrency.title.toLowerCase();
exchangeViewModel.receiveAddress =
await fetchParsedAddress(
context, domain, ticker);
},
)),
)
],

View file

@ -34,7 +34,8 @@ class ExchangeCard extends StatefulWidget {
this.addressFocusNode,
this.hasAllAmount = false,
this.allAmount,
this.onPushPasteButton})
this.onPushPasteButton,
this.onPushAddressBookButton})
: super(key: key);
final List<CryptoCurrency> currencies;
@ -59,6 +60,7 @@ class ExchangeCard extends StatefulWidget {
final bool hasAllAmount;
final Function allAmount;
final Function(BuildContext context) onPushPasteButton;
final Function(BuildContext context) onPushAddressBookButton;
@override
ExchangeCardState createState() => ExchangeCardState();
@ -321,6 +323,7 @@ class ExchangeCardState extends State<ExchangeCard> {
buttonColor: widget.addressButtonsColor,
validator: widget.addressTextFieldValidator,
onPushPasteButton: widget.onPushPasteButton,
onPushAddressBookButton: widget.onPushAddressBookButton
),
)
: Padding(
@ -366,6 +369,8 @@ class ExchangeCardState extends State<ExchangeCard> {
setState(() =>
addressController.text =
contact.address);
widget.onPushAddressBookButton
?.call(context);
}
},
child: Container(

View file

@ -101,7 +101,7 @@ class QRWidget extends StatelessWidget {
),
),
Padding(
padding: EdgeInsets.only(top: 16, bottom: 16),
padding: EdgeInsets.only(top: 10, bottom: 10),
child: Builder(
builder: (context) => Observer(
builder: (context) => GestureDetector(
@ -164,7 +164,7 @@ class QRWidget extends StatelessWidget {
addressListViewModel.emoji,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13,
fontSize: 26,
),
)
)

View file

@ -156,8 +156,10 @@ class SendCardState extends State<SendCard>
output.resetParsedAddress();
await output.fetchParsedAddress(context);
},
onPushAddressBookButton: (context) =>
output.resetParsedAddress(),
onPushAddressBookButton: (context) async {
output.resetParsedAddress();
await output.fetchParsedAddress(context);
},
validator: validator,
);
}),

View file

@ -0,0 +1,90 @@
import 'package:cake_wallet/src/screens/yat/widgets/yat_bar.dart';
import 'package:cake_wallet/src/screens/yat/widgets/yat_page_indicator.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
import 'package:lottie/lottie.dart';
class FirstIntroduction extends StatelessWidget {
FirstIntroduction({this.onClose, this.onNext});
static const aspectRatioImage = 1.133;
final VoidCallback onClose;
final VoidCallback onNext;
final animation = Lottie.asset('assets/animation/anim1.json');
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
return Container(
height: screenHeight,
width: screenWidth,
color: Colors.white,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(top: 40, bottom: 40),
content: Column(
children: [
Container(
height: 45,
padding: EdgeInsets.only(left: 24, right: 24),
child: YatBar(onClose: () => Navigator.of(context).pop())
),
animation,
Container(
padding: EdgeInsets.only(left: 30, right: 30),
child: Column(
children: [
Text(
'Send and receive crypto more easily with Yat',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Colors.black,
decoration: TextDecoration.none,
)
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Text(
'Cake Wallet users can now send and receive all their favorite currencies with a one-of-a-kind emoji-based username.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Lato',
color: Colors.black,
decoration: TextDecoration.none,
)
)
)
]
)
)
]
),
bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
bottomSection: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
PrimaryButton(
text: 'Next',
textColor: Colors.white,
color: Palette.protectiveBlue,
onPressed: onNext
),
Padding(
padding: EdgeInsets.only(top: 24),
child: YatPageIndicator(filled: 0)
)
]
),
)
);
}
}

View file

@ -0,0 +1,89 @@
import 'package:cake_wallet/src/screens/yat/widgets/yat_bar.dart';
import 'package:cake_wallet/src/screens/yat/widgets/yat_page_indicator.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
import 'package:lottie/lottie.dart';
class SecondIntroduction extends StatelessWidget {
SecondIntroduction({this.onClose, this.onNext});
final VoidCallback onClose;
final VoidCallback onNext;
final animation = Lottie.asset('assets/animation/anim2.json');
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
return Container(
height: screenHeight,
width: screenWidth,
color: Colors.white,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(top: 40, bottom: 40),
content: Column(
children: [
Container(
height: 45,
padding: EdgeInsets.only(left: 24, right: 24),
child: YatBar(onClose: onClose)
),
animation,
Padding(
padding: EdgeInsets.only(top: 40, left: 30, right: 30),
child: Column(
children: [
Text(
'One emoji address to rule them all',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Colors.black,
decoration: TextDecoration.none,
)
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Text(
'Your Yat is a single unique emoji address that replaces all of your long hexadecimal addresses for all of your currencies.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Lato',
color: Colors.black,
decoration: TextDecoration.none,
)
)
)
]
),
),
],
),
bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
bottomSection: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
PrimaryButton(
text: 'Next',
textColor: Colors.white,
color: Palette.protectiveBlue,
onPressed: onNext
),
Padding(
padding: EdgeInsets.only(top: 24),
child: YatPageIndicator(filled: 1)
)
]
),
)
);
}
}

View file

@ -0,0 +1,109 @@
import 'package:cake_wallet/src/screens/yat/widgets/yat_bar.dart';
import 'package:cake_wallet/src/screens/yat/widgets/yat_page_indicator.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
import 'package:lottie/lottie.dart';
class ThirdIntroduction extends StatelessWidget {
ThirdIntroduction({this.onClose, this.onGet, this.onConnect});
final VoidCallback onClose;
final VoidCallback onGet;
final VoidCallback onConnect;
final animation = Lottie.asset('assets/animation/anim3.json');
@override
Widget build(BuildContext context) {
final screenHeight = MediaQuery.of(context).size.height;
final screenWidth = MediaQuery.of(context).size.width;
return Container(
height: screenHeight,
width: screenWidth,
color: Colors.white,
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(top: 40, bottom: 40),
content: Column(
children: [
Container(
height: 90,
padding: EdgeInsets.only(left: 24, right: 24),
child: YatBar(onClose: onClose)
),
animation,
Padding(
padding: EdgeInsets.only(top: 40, left: 30, right: 30),
child: Column(
children: [
Text(
'Yat plays nicely with others',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Colors.black,
decoration: TextDecoration.none,
)
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Text(
'Yats live outside of Cake Wallet, too. Any wallet address on earth can be replaced with a Yat!',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Lato',
color: Colors.black,
decoration: TextDecoration.none,
)
)
)
]
)
),
],
),
bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
bottomSection: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
PrimaryIconButton(
text: 'Get your Yat',
textColor: Colors.white,
color: Palette.protectiveBlue,
borderColor: Palette.protectiveBlue,
iconColor: Colors.white,
iconBackgroundColor: Colors.transparent,
iconData: CupertinoIcons
.arrow_up_right_square,
mainAxisAlignment: MainAxisAlignment.end,
onPressed: onGet),
Padding(
padding: EdgeInsets.only(top: 12),
child: PrimaryIconButton(
text: 'Connect an existing Yat',
textColor: Colors.black,
color: Palette.blueAlice,
borderColor: Palette.blueAlice,
iconColor: Colors.black,
iconBackgroundColor: Colors.transparent,
iconData: CupertinoIcons
.arrow_up_right_square,
mainAxisAlignment: MainAxisAlignment.end,
onPressed: onConnect)
),
Padding(
padding: EdgeInsets.only(top: 24),
child: YatPageIndicator(filled: 2)
)
]
),
)
);
}
}

View file

@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
class YatPageIndicator extends StatelessWidget {
YatPageIndicator({this.filled});
final int filled;
@override
Widget build(BuildContext context) {
return Container(
width: 44,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: List.generate(3, (index) {
final size = 8.0;
final isFilled = index == filled;
return Container(
height: size,
width: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: isFilled
? Palette.frostySky
: Palette.stateGray.withOpacity(0.1)
)
);
})
)
);
}
}

View file

@ -1,8 +1,7 @@
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/src/screens/yat/widgets/yat_bar.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
@ -11,22 +10,13 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:lottie/lottie.dart';
class YatAlert extends StatelessWidget {
YatAlert({@required this.wallet, this.isYatDevMode = false})
: baseUrl = isYatDevMode ? _baseDevUrl : _baseReleaseUrl,
address = wallet.walletAddresses.address;
YatAlert(this.yatStore)
: baseUrl = isYatDevMode ? baseDevUrl : baseReleaseUrl;
final WalletBase wallet;
final bool isYatDevMode;
final String address;
final YatStore yatStore;
final String baseUrl;
static const aspectRatioImage = 1.133;
static const _baseDevUrl = 'https://yat.fyi';
static const _baseReleaseUrl = 'https://y.at';
static const _signInSuffix = '/partner/CW/link-email';
static const _createSuffix = '/create';
static const _queryParameter = '?addresses=';
final image = Image.asset('assets/images/yat_crypto.png');
final anim = Lottie.asset('assets/animation/anim1.json');
final animation = Lottie.asset('assets/animation/anim1.json');
@override
Widget build(BuildContext context) {
@ -42,15 +32,11 @@ class YatAlert extends StatelessWidget {
content: Column(
children: [
Container(
height: 45, // 90
height: 45,
padding: EdgeInsets.only(left: 24, right: 24),
child: YatBar(onClose: () => Navigator.of(context).pop())
),
anim,
// AspectRatio(
// aspectRatio: aspectRatioImage,
// child: FittedBox(child: image, fit: BoxFit.fill)
// ),
animation,
Container(
padding: EdgeInsets.only(left: 30, right: 30),
child: Column(
@ -100,7 +86,7 @@ class YatAlert extends StatelessWidget {
.arrow_up_right_square,
mainAxisAlignment: MainAxisAlignment.end,
onPressed: () {
final url = baseUrl + _createSuffix;
final url = baseUrl + createSuffix;
launch(url);
}),
Padding(
@ -116,8 +102,12 @@ class YatAlert extends StatelessWidget {
.arrow_up_right_square,
mainAxisAlignment: MainAxisAlignment.end,
onPressed: () {
final url = baseUrl + _signInSuffix + _queryParameter +
_defineTag() + '%3D' + address;
String url = baseUrl + signInSuffix;
final parameters =
yatStore.defineQueryParameters();
if (parameters.isNotEmpty) {
url += queryParameter + parameters;
}
launch(url);
})
)
@ -126,24 +116,4 @@ class YatAlert extends StatelessWidget {
)
);
}
String _defineTag() {
String tag;
switch (wallet.type) {
case WalletType.monero:
tag = address.startsWith('4')
? '0x1001'
: '0x1002';
break;
case WalletType.bitcoin:
tag = '0x1003';
break;
case WalletType.litecoin:
tag = '0x3fff';
break;
default:
tag = '0x3fff';
}
return tag;
}
}

View file

@ -0,0 +1,178 @@
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/yat/widgets/first_introduction.dart';
import 'package:cake_wallet/src/screens/yat/widgets/second_introduction.dart';
import 'package:cake_wallet/src/screens/yat/widgets/third_introduction.dart';
import 'package:cake_wallet/src/screens/yat/widgets/yat_close_button.dart';
import 'package:cake_wallet/src/widgets/alert_background.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/material.dart';
import 'package:animate_do/animate_do.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:url_launcher/url_launcher.dart';
class YatPopup extends StatelessWidget {
YatPopup({this.dashboardViewModel, this.onClose})
: baseUrl = isYatDevMode ? baseDevUrl : baseReleaseUrl;
static const durationInMilliseconds = 250;
final DashboardViewModel dashboardViewModel;
final VoidCallback onClose;
final String baseUrl;
final image = Image.asset('assets/images/emoji_popup.png');
@override
Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
return Stack(
clipBehavior: Clip.none,
alignment: Alignment.bottomCenter,
children: [
AlertBackground(
child: Container()
),
SlideInUp(
from: 420,
duration: Duration(milliseconds: durationInMilliseconds),
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24)),
child: Container(
height: 420,
color: Colors.white,
padding: EdgeInsets.fromLTRB(24, 15, 24, 24),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
children: [
YatCloseButton(onClose: onClose)
]
),
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 64,
width: 165,
alignment: Alignment.center,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius
.all(Radius.circular(32)),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.05),
blurRadius: 15,
offset: Offset(0, 5)
)
]
),
child: image
)
]
)
]
),
Container(
padding: EdgeInsets.only(left: 6, right: 6),
child: Column(
children: [
Text(
'Your wallet address can be emojified.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Colors.black,
decoration: TextDecoration.none,
)
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Text(
'You can now send and receive crypto in Cake Wallet with your Yat - a short, emoji-based username. Manage Yats at any time on the settings screen',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
fontFamily: 'Lato',
color: Colors.black,
decoration: TextDecoration.none,
)
)
)
]
)
),
PrimaryButton(
text: 'Learn More',
textColor: Colors.white,
color: Palette.protectiveBlue,
onPressed: () => dashboardViewModel
.isShowFirstYatIntroduction = true
)
],
)
)
),
),
Observer(builder: (_) => dashboardViewModel.isShowFirstYatIntroduction
? SlideInRight(
from: screenWidth,
duration: Duration(milliseconds: durationInMilliseconds),
child: FirstIntroduction(
onClose: onClose,
onNext: () => dashboardViewModel
.isShowSecondYatIntroduction = true
))
: Container()
),
Observer(builder: (_) => dashboardViewModel.isShowSecondYatIntroduction
? SlideInRight(
from: screenWidth,
duration: Duration(milliseconds: durationInMilliseconds),
child: SecondIntroduction(
onClose: onClose,
onNext: () => dashboardViewModel
.isShowThirdYatIntroduction = true
))
: Container()
),
Observer(builder: (_) => dashboardViewModel.isShowThirdYatIntroduction
? SlideInRight(
from: screenWidth,
duration: Duration(milliseconds: durationInMilliseconds),
child: ThirdIntroduction(
onClose: onClose,
onGet: () {
final url = baseUrl + createSuffix;
launch(url);
},
onConnect: () {
String url = baseUrl + signInSuffix;
final parameters = dashboardViewModel
.yatStore.defineQueryParameters();
if (parameters.isNotEmpty) {
url += queryParameter + parameters;
}
launch(url);
}
))
: Container()
)
],
);
}
}

View file

@ -0,0 +1,166 @@
import 'package:cake_wallet/core/transaction_history.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/entities/balance.dart';
import 'package:cake_wallet/entities/transaction_info.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/bitcoin/electrum_wallet.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/monero/monero_subaddress_list.dart';
import 'package:cake_wallet/monero/monero_wallet.dart';
import 'dart:convert';
import 'package:cake_wallet/store/yat/yat_exception.dart';
import 'package:http/http.dart';
part 'yat_store.g.dart';
const baseDevUrl = 'https://yat.fyi';
const baseReleaseUrl = 'https://y.at';
const signInSuffix = '/partner/CW/link-email';
const createSuffix = '/create';
const queryParameter = '?addresses=';
const requestDevUrl = 'https://a.yat.fyi/emoji_id/';
const requestReleaseUrl = 'https://a.y.at/emoji_id/';
const isYatDevMode = true;
Future<List<String>> fetchYatAddress(String emojiId, String ticker) async {
final requestURL = isYatDevMode ? requestDevUrl : requestReleaseUrl;
final url = requestURL + emojiId + '/' + ticker.toUpperCase();
final response = await get(url);
if (response.statusCode != 200) {
throw YatException(text: response.body.toString());
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final result = responseJSON['result'] as List<dynamic>;
if (result?.isEmpty ?? true) {
return [];
}
final List<String> addresses = [];
for (var elem in result) {
final yatAddress = elem['data'] as String;
if (yatAddress?.isNotEmpty ?? false) {
addresses.add(yatAddress);
}
}
return addresses;
}
class YatStore = YatStoreBase with _$YatStore;
abstract class YatStoreBase with Store {
YatStoreBase({@required this.appStore}) {
_wallet ??= appStore.wallet;
emoji = _wallet?.walletInfo?.yatEmojiId ?? '';
refreshToken = _wallet?.walletInfo?.yatToken ?? '';
reaction((_) => appStore.wallet, _onWalletChange);
reaction((_) => emoji, (String emoji) => _onEmojiChange());
}
AppStore appStore;
@observable
String emoji;
@observable
String refreshToken;
@observable
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo>
_wallet;
@action
void _onWalletChange(
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
TransactionInfo>
wallet) {
this._wallet = wallet;
emoji = wallet?.walletInfo?.yatEmojiId ?? '';
refreshToken = wallet?.walletInfo?.yatToken ?? '';
}
@action
void _onEmojiChange() {
try {
final walletInfo = _wallet.walletInfo;
if (walletInfo == null) {
return;
}
walletInfo.yatEid = emoji;
walletInfo.yatRefreshToken = refreshToken;
if (walletInfo.isInBox) {
walletInfo.save();
}
} catch (e) {
print(e.toString());
}
}
String defineQueryParameters() {
String parameters = '';
switch (_wallet.type) {
case WalletType.monero:
final wallet = _wallet as MoneroWallet;
final subaddressList = MoneroSubaddressList();
var isFirstAddress = true;
wallet.walletAddresses.accountList.accounts.forEach((account) {
subaddressList.update(accountIndex: account.id);
subaddressList.subaddresses.forEach((subaddress) {
if (!isFirstAddress) {
parameters += '%7C';
} else {
isFirstAddress = !isFirstAddress;
}
parameters += subaddress.address.startsWith('4')
? '0x1001%3D'
: '0x1002%3D';
parameters += subaddress.address;
});
});
break;
case WalletType.bitcoin:
final wallet = _wallet as ElectrumWallet;
var isFirstAddress = true;
wallet.walletAddresses.addresses.forEach((record) {
if (!isFirstAddress) {
parameters += '%7C';
} else {
isFirstAddress = !isFirstAddress;
}
parameters += '0x1003%3D' + record.address;
});
break;
case WalletType.litecoin:
final wallet = _wallet as ElectrumWallet;
var isFirstAddress = true;
wallet.walletAddresses.addresses.forEach((record) {
if (!isFirstAddress) {
parameters += '%7C';
} else {
isFirstAddress = !isFirstAddress;
}
parameters += '0x3fff%3D' + record.address;
});
break;
default:
parameters = '';
}
return parameters;
}
}

View file

@ -1,12 +0,0 @@
import 'package:mobx/mobx.dart';
part 'yat_store.g.dart';
class YatStore = YatStoreBase with _$YatStore;
abstract class YatStoreBase with Store {
YatStoreBase() : emoji = '';
@observable
String emoji;
}

View file

@ -12,6 +12,7 @@ import 'package:cake_wallet/entities/transaction_info.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cake_wallet/utils/mobx.dart';
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
@ -46,6 +47,7 @@ abstract class DashboardViewModelBase with Store {
this.tradeFilterStore,
this.transactionFilterStore,
this.settingsStore,
this.yatStore,
this.ordersStore}) {
filterItems = {
S.current.transactions: [
@ -86,6 +88,9 @@ abstract class DashboardViewModelBase with Store {
type = wallet.type;
isOutdatedElectrumWallet =
wallet.type == WalletType.bitcoin && wallet.seed.split(' ').length < 24;
isShowFirstYatIntroduction = false;
isShowSecondYatIntroduction = false;
isShowThirdYatIntroduction = false;
final _wallet = wallet;
if (_wallet is MoneroWallet) {
@ -147,6 +152,15 @@ abstract class DashboardViewModelBase with Store {
@observable
String subname;
@observable
bool isShowFirstYatIntroduction;
@observable
bool isShowSecondYatIntroduction;
@observable
bool isShowThirdYatIntroduction;
@computed
String get address => wallet.walletAddresses.address;
@ -208,6 +222,8 @@ abstract class DashboardViewModelBase with Store {
SettingsStore settingsStore;
YatStore yatStore;
TradesStore tradesStore;
OrdersStore ordersStore;

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/src/screens/yat/yat_alert.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/cupertino.dart';
import 'package:mobx/mobx.dart';
@ -50,6 +51,7 @@ List<TransactionPriority> priorityForWalletType(WalletType type) {
abstract class SettingsViewModelBase with Store {
SettingsViewModelBase(
this._settingsStore,
this._yatStore,
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
TransactionInfo>
wallet)
@ -162,7 +164,7 @@ abstract class SettingsViewModelBase with Store {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return YatAlert(wallet: wallet, isYatDevMode: true);
return YatAlert(_yatStore);
});
},
),
@ -213,6 +215,7 @@ abstract class SettingsViewModelBase with Store {
final Map<String, String> itemHeaders;
List<List<SettingsListItem>> sections;
final SettingsStore _settingsStore;
final YatStore _yatStore;
final WalletType _walletType;
final BiometricAuth _biometricAuth;

View file

@ -1,4 +1,4 @@
import 'package:cake_wallet/store/yat_store.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';

View file

@ -1,31 +0,0 @@
import 'dart:convert';
import 'package:cake_wallet/yat/yat_exception.dart';
import 'package:http/http.dart';
Future<List<String>> fetchYatAddress(String emojiId, String ticker) async {
const _requestURL = 'https://a.y.at/emoji_id/';
final url = _requestURL + emojiId + '/' + ticker.toUpperCase();
final response = await get(url);
if (response.statusCode != 200) {
throw YatException(text: response.body.toString());
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final result = responseJSON['result'] as List<dynamic>;
if (result?.isEmpty ?? true) {
return [];
}
final List<String> addresses = [];
for (var elem in result) {
final yatAddress = elem['data'] as String;
if (yatAddress?.isNotEmpty ?? false) {
addresses.add(yatAddress);
}
}
return addresses;
}

View file

@ -15,6 +15,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.41.2"
animate_do:
dependency: "direct main"
description:
name: animate_do
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
archive:
dependency: "direct main"
description:

View file

@ -59,6 +59,7 @@ dependencies:
flutter_spinkit: ^5.0.0
uni_links: ^0.4.0
lottie: ^0.7.0
animate_do: ^2.0.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.