diff --git a/assets/images/badge_discount.png b/assets/images/badge_discount.png new file mode 100644 index 000000000..64c8789c5 Binary files /dev/null and b/assets/images/badge_discount.png differ diff --git a/assets/images/card.png b/assets/images/card.png new file mode 100644 index 000000000..58935bdac Binary files /dev/null and b/assets/images/card.png differ diff --git a/assets/images/filter.png b/assets/images/filter.png new file mode 100644 index 000000000..dc47944c0 Binary files /dev/null and b/assets/images/filter.png differ diff --git a/assets/images/profile.png b/assets/images/profile.png new file mode 100644 index 000000000..d7dfe2508 Binary files /dev/null and b/assets/images/profile.png differ diff --git a/assets/images/search_icon.png b/assets/images/search_icon.png new file mode 100644 index 000000000..d9d71a4d7 Binary files /dev/null and b/assets/images/search_icon.png differ diff --git a/cw_haven/pubspec.lock b/cw_haven/pubspec.lock index 37e6b72b7..f9b6c4890 100644 --- a/cw_haven/pubspec.lock +++ b/cw_haven/pubspec.lock @@ -169,13 +169,6 @@ packages: relative: true source: path version: "0.0.1" - cw_monero: - dependency: "direct main" - description: - path: "../cw_monero" - relative: true - source: path - version: "0.0.1" dart_style: dependency: transitive description: diff --git a/ios/Podfile.lock b/ios/Podfile.lock index d90ef8ca3..2a1ce2747 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -98,6 +98,9 @@ PODS: - Flutter (1.0.0) - flutter_secure_storage (3.3.1): - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) - local_auth (0.0.1): - Flutter - MTBBarcodeScanner (5.0.11) @@ -115,6 +118,9 @@ PODS: - Flutter - shared_preferences (0.0.1): - Flutter + - sqflite (0.0.2): + - Flutter + - FMDB (>= 2.7.5) - SwiftProtobuf (1.12.0) - SwiftyGif (5.3.0) - uni_links (0.0.1): @@ -145,6 +151,7 @@ DEPENDENCIES: - permission_handler (from `.symlinks/plugins/permission_handler/ios`) - share (from `.symlinks/plugins/share/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) - uni_links (from `.symlinks/plugins/uni_links/ios`) - UnstoppableDomainsResolution (~> 4.0.0) - url_launcher (from `.symlinks/plugins/url_launcher/ios`) @@ -156,6 +163,7 @@ SPEC REPOS: - CryptoSwift - DKImagePickerController - DKPhotoGallery + - FMDB - MTBBarcodeScanner - Reachability - SDWebImage @@ -196,6 +204,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/share/ios" shared_preferences: :path: ".symlinks/plugins/shared_preferences/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" uni_links: :path: ".symlinks/plugins/uni_links/ios" url_launcher: @@ -218,6 +228,7 @@ SPEC CHECKSUMS: file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62 @@ -227,6 +238,7 @@ SPEC CHECKSUMS: SDWebImage: a990c053fff71e388a10f3357edb0be17929c9c5 share: 0b2c3e82132f5888bccca3351c504d0003b3b410 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699 SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40 uni_links: d97da20c7701486ba192624d99bffaaffcfc298a @@ -236,4 +248,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: ae71bdf0eb731a1ffc399c122f6aa4dea0cb5f6f -COCOAPODS: 1.11.2 +COCOAPODS: 1.11.3 diff --git a/lib/di.dart b/lib/di.dart index 3cc4dacae..27923cfa4 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -5,6 +5,12 @@ import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/haven/haven.dart'; import 'package:cake_wallet/haven/haven.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; +import 'package:cake_wallet/src/screens/cake_pay/auth/create_account_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/auth/forgot_password_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/auth/login_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart'; +import 'package:cake_wallet/src/screens/cake_pay/cards/buy_gift_card.dart'; +import 'package:cake_wallet/src/screens/cake_pay/cards/manage_cards_page.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cake_wallet/core/backup_service.dart'; @@ -639,5 +645,17 @@ Future setup( getIt.registerFactory(() => AddressResolver(yatService: getIt.get())); + getIt.registerFactory(() => WelcomePage()); + + getIt.registerFactory(() => LoginPage()); + + getIt.registerFactory(() => CreateAccountPage()); + + getIt.registerFactory(() => ForgotPassword()); + + getIt.registerFactory(() => ManageCardsPage()); + + getIt.registerFactory(() => BuyGiftCardPage()); + _isSetupFinished = true; } diff --git a/lib/router.dart b/lib/router.dart index acfb18684..b2ef23d6c 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -5,6 +5,12 @@ import 'package:cake_wallet/src/screens/backup/backup_page.dart'; import 'package:cake_wallet/src/screens/backup/edit_backup_password_page.dart'; import 'package:cake_wallet/src/screens/buy/buy_webview_page.dart'; import 'package:cake_wallet/src/screens/buy/pre_order_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/auth/create_account_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/auth/forgot_password_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/auth/login_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart'; +import 'package:cake_wallet/src/screens/cake_pay/cards/buy_gift_card.dart'; +import 'package:cake_wallet/src/screens/cake_pay/cards/manage_cards_page.dart'; import 'package:cake_wallet/src/screens/order_details/order_details_page.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart'; @@ -402,6 +408,24 @@ Route createRoute(RouteSettings settings) { getIt.get( param1: args)); + case Routes.cakePayWelcomePage: + return CupertinoPageRoute(builder: (_) => getIt.get()); + + case Routes.cakePayLoginPage: + return CupertinoPageRoute( builder: (_) => getIt.get()); + + case Routes.cakePayCreateAccountPage: + return CupertinoPageRoute( builder: (_) => getIt.get()); + + case Routes.cakePayForgotPasswordPage: + return CupertinoPageRoute(builder: (_) => getIt.get()); + + case Routes.manageCardsPage: + return CupertinoPageRoute(builder: (_) => getIt.get()); + + case Routes.buyGiftCardPage: + return CupertinoPageRoute(builder: (_) => getIt.get()); + default: return MaterialPageRoute( builder: (_) => Scaffold( diff --git a/lib/routes.dart b/lib/routes.dart index 23e236023..0ec0efd0d 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -60,4 +60,10 @@ class Routes { static const moneroRestoreWalletFromWelcome = '/monero_restore_wallet'; static const moneroNewWalletFromWelcome = '/monero_new_wallet'; static const addressPage = '/address_page'; -} \ No newline at end of file + static const cakePayWelcomePage = '/cake_pay_welcome_page'; + static const cakePayCreateAccountPage = '/cake_pay_create_account_page'; + static const cakePayLoginPage = '/cake_pay_login_page'; + static const cakePayForgotPasswordPage = '/cake_pay_forgot_password_page'; + static const manageCardsPage = '/manage_cards_page'; + static const buyGiftCardPage = '/buy_gift_card_page'; +} diff --git a/lib/src/screens/cake_pay/auth/create_account_page.dart b/lib/src/screens/cake_pay/auth/create_account_page.dart new file mode 100644 index 000000000..32ec228e8 --- /dev/null +++ b/lib/src/screens/cake_pay/auth/create_account_page.dart @@ -0,0 +1,94 @@ +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +class CreateAccountPage extends BasePage { + CreateAccountPage() : _formKey = GlobalKey(); + + final GlobalKey _formKey; + + @override + Widget middle(BuildContext context) { + return Text( + S.current.sign_up, + style: TextStyle( + fontSize: 22, + fontFamily: 'Lato', + fontWeight: FontWeight.w900, + ), + ); + } + + @override + Widget body(BuildContext context) { + return ScrollableWithBottomSection( + contentPadding: EdgeInsets.all(24), + content: Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BaseTextFormField( + hintText: 'Email Address *', + ), + SizedBox(height: 20), + BaseTextFormField( + hintText: 'Password *', + ), + ], + ), + ), + bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24), + bottomSection: Column( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + PrimaryButton( + text: S.of(context).create_account, + onPressed: () {}, + color: Theme.of(context).accentTextTheme.body2.color, + textColor: Colors.white, + ), + SizedBox( + height: 20, + ), + RichText( + textAlign: TextAlign.center, + text: TextSpan( + text: 'By creating account you agree to the ', + style: TextStyle( + color: Color(0xff7A93BA), + fontSize: 12, + fontFamily: 'Lato', + ), + children: [ + TextSpan( + text: S.of(context).settings_terms_and_conditions, + style: TextStyle( + color: Theme.of(context).accentTextTheme.body2.color, + fontWeight: FontWeight.w700, + ), + ), + TextSpan(text: ' and '), + TextSpan( + text: S.of(context).privacy_policy, + style: TextStyle( + color: Theme.of(context).accentTextTheme.body2.color, + fontWeight: FontWeight.w700, + ), + ), + TextSpan(text: ' by CakePay'), + ], + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/src/screens/cake_pay/auth/forgot_password_page.dart b/lib/src/screens/cake_pay/auth/forgot_password_page.dart new file mode 100644 index 000000000..990380d03 --- /dev/null +++ b/lib/src/screens/cake_pay/auth/forgot_password_page.dart @@ -0,0 +1,55 @@ +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +class ForgotPassword extends BasePage { + @override + Color get titleColor => Colors.black; + + @override + Widget middle(BuildContext context) { + return Text( + S.current.forgot_password, + style: TextStyle( + fontSize: 22, + fontFamily: 'Lato', + fontWeight: FontWeight.w900, + ), + ); + } + + @override + Widget body(BuildContext context) { + return ScrollableWithBottomSection( + contentPadding: EdgeInsets.all(24), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BaseTextFormField( + hintText: 'Email Address*', + ), + SizedBox(height: 20), + ], + ), + bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24), + bottomSection: Column( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + PrimaryButton( + text: S.of(context).reset_password, + onPressed: () {}, + color: Theme.of(context).accentTextTheme.body2.color, + textColor: Colors.white, + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/src/screens/cake_pay/auth/login_page.dart b/lib/src/screens/cake_pay/auth/login_page.dart new file mode 100644 index 000000000..e427799a3 --- /dev/null +++ b/lib/src/screens/cake_pay/auth/login_page.dart @@ -0,0 +1,80 @@ +import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +class LoginPage extends BasePage { + LoginPage() : _formKey = GlobalKey(); + + final GlobalKey _formKey; + @override + Color get titleColor => Colors.black; + + @override + Widget middle(BuildContext context) { + return Text( + S.current.login, + style: TextStyle( + fontSize: 22, + fontFamily: 'Lato', + fontWeight: FontWeight.w900, + ), + ); + } + + @override + Widget body(BuildContext context) { + return ScrollableWithBottomSection( + contentPadding: EdgeInsets.all(24), + content: Form( + key: _formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BaseTextFormField( + hintText: 'Email Address', + ), + SizedBox(height: 20), + BaseTextFormField( + hintText: 'Password', + ), + ], + ), + ), + bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24), + bottomSection: Column( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + PrimaryButton( + text: S.of(context).login, + onPressed: () {}, + color: Theme.of(context).accentTextTheme.body2.color, + textColor: Colors.white, + ), + SizedBox( + height: 20, + ), + InkWell( + onTap: () => Navigator.of(context).pushNamed(Routes.cakePayForgotPasswordPage), + child: Text( + S.of(context).forgot_password, + style: TextStyle( + color: Palette.blueCraiola, + fontSize: 16, + fontWeight: FontWeight.w900, + ), + ), + ) + ], + ), + ], + ), + ); + } +} diff --git a/lib/src/screens/cake_pay/auth/welcome_page.dart b/lib/src/screens/cake_pay/auth/welcome_page.dart new file mode 100644 index 000000000..234abb887 --- /dev/null +++ b/lib/src/screens/cake_pay/auth/welcome_page.dart @@ -0,0 +1,95 @@ +import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +class WelcomePage extends BasePage { + @override + Color get titleColor => Colors.black; + + @override + Widget middle(BuildContext context) { + return Text( + S.current.welcome_to_cakepay, + style: TextStyle( + fontSize: 22, + fontFamily: 'Lato', + fontWeight: FontWeight.w900, + ), + ); + } + + @override + Widget body(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + SizedBox(height: 100), + Text( + S.of(context).about_cake_pay, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w400, + fontFamily: 'Lato', + color: Theme.of(context).primaryTextTheme.title.color, + ), + ), + SizedBox(height: 20), + Text( + S.of(context).cake_pay_account_note, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w400, + fontFamily: 'Lato', + color: Theme.of(context).primaryTextTheme.title.color, + ), + ), + ], + ), + Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + PrimaryButton( + text: S.of(context).create_account, + onPressed: () => Navigator.of(context).pushNamed(Routes.cakePayCreateAccountPage), + color: Theme.of(context).accentTextTheme.body2.color, + textColor: Colors.white, + ), + SizedBox( + height: 16, + ), + Text( + S.of(context).already_have_account, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w500, + fontFamily: 'Lato', + color: Theme.of(context).primaryTextTheme.title.color, + ), + ), + SizedBox(height: 8), + InkWell( + onTap: () => Navigator.of(context).pushNamed(Routes.cakePayLoginPage), + child: Text( + S.of(context).login, + style: TextStyle( + color: Palette.blueCraiola, + fontSize: 16, + fontWeight: FontWeight.w900, + ), + ), + ) + ], + ) + ], + ), + ); + } +} diff --git a/lib/src/screens/cake_pay/cake_pay.dart b/lib/src/screens/cake_pay/cake_pay.dart new file mode 100644 index 000000000..b6e794905 --- /dev/null +++ b/lib/src/screens/cake_pay/cake_pay.dart @@ -0,0 +1 @@ +export 'auth/welcome_page.dart'; \ No newline at end of file diff --git a/lib/src/screens/cake_pay/cards/buy_gift_card.dart b/lib/src/screens/cake_pay/cards/buy_gift_card.dart new file mode 100644 index 000000000..a3f611067 --- /dev/null +++ b/lib/src/screens/cake_pay/cards/buy_gift_card.dart @@ -0,0 +1,96 @@ +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/widgets/keyboard_done_button.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/themes/theme_base.dart'; +import 'package:flutter/material.dart'; +import 'package:keyboard_actions/keyboard_actions.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + + +class BuyGiftCardPage extends BasePage { + BuyGiftCardPage(): _amountFieldFocus = FocusNode(), + _amountController = TextEditingController(); + @override + String get title => 'Enter Amount'; + + @override + Color get titleColor => Colors.white; + + @override + bool get extendBodyBehindAppBar => true; + + @override + AppBarStyle get appBarStyle => AppBarStyle.transparent; + + Color get textColor => + currentTheme.type == ThemeType.dark ? Colors.white : Color(0xff393939); + + final TextEditingController _amountController; + final FocusNode _amountFieldFocus; + + + + @override + Widget body(BuildContext context) { + return KeyboardActions( + disableScroll: true, + config: KeyboardActionsConfig( + keyboardActionsPlatform: KeyboardActionsPlatform.IOS, + keyboardBarColor: Theme.of(context).accentTextTheme.body2.backgroundColor, + nextFocus: false, + actions: [ + KeyboardActionsItem( + focusNode: _amountFieldFocus, + toolbarButtons: [(_) => KeyboardDoneButton()], + ), + ]), + child: Container( + color: Theme.of(context).backgroundColor, + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.zero, + content: + Container( + padding: EdgeInsets.symmetric(horizontal: 14), + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(24), + bottomRight: Radius.circular(24)), + gradient: LinearGradient(colors: [ + Theme.of(context).primaryTextTheme.subhead.color, + Theme.of(context).primaryTextTheme.subhead.decorationColor, + ], begin: Alignment.topLeft, end: Alignment.bottomRight), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + SizedBox(height: 200), + + BaseTextFormField(controller: _amountController, focusNode: _amountFieldFocus, ) + ], + ), + ), + bottomSection: + Column( + children: [ + + Padding( + padding: EdgeInsets.only(bottom: 12), + child: PrimaryButton( + onPressed: () {}, + text: S.of(context).continue_text, + color: Theme.of(context).accentTextTheme.body2.color, + textColor: Colors.white, + ), + ), + SizedBox(height: 20), + + SizedBox(height: 10) + ], + ) , + ) ,), + ); + } +} diff --git a/lib/src/screens/cake_pay/cards/manage_cards_page.dart b/lib/src/screens/cake_pay/cards/manage_cards_page.dart new file mode 100644 index 000000000..5e14cd703 --- /dev/null +++ b/lib/src/screens/cake_pay/cards/manage_cards_page.dart @@ -0,0 +1,219 @@ +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/card_menu.dart'; +import 'package:cake_wallet/src/widgets/market_place_item.dart'; +import 'package:cake_wallet/themes/theme_base.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +class ManageCardsPage extends BasePage { + @override + Color get backgroundLightColor => currentTheme.type == ThemeType.bright ? Colors.transparent : Colors.white; + + @override + Color get backgroundDarkColor => Colors.transparent; + + @override + Color get titleColor => currentTheme.type == ThemeType.bright ? Colors.white : Colors.black; + + @override + Widget Function(BuildContext, Widget) get rootWrapper => (BuildContext context, Widget scaffold) => Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Theme.of(context).accentColor, + Theme.of(context).scaffoldBackgroundColor, + Theme.of(context).primaryColor, + ], + begin: Alignment.topRight, + end: Alignment.bottomLeft, + ), + ), + child: scaffold, + ); + + @override + bool get resizeToAvoidBottomInset => false; + + @override + Widget get endDrawer => CardMenu(); + + @override + Widget middle(BuildContext context) { + return Text( + S.of(context).manage_cards, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w500, + color: Theme.of(context).accentTextTheme.display3.backgroundColor, + ), + ); + } + + final ScrollController _scrollController = ScrollController(); + + @override + Widget trailing(BuildContext context) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + _TrailingIcon( + asset: 'assets/images/card.png', + onPressed: () {}, + ), + SizedBox(width: 16), + _TrailingIcon( + asset: 'assets/images/profile.png', + onPressed: () {}, + ), + ], + ); + } + + @override + Widget body(BuildContext context) { + final filterIcon = Image.asset( + 'assets/images/filter.png', + color: Theme.of(context).textTheme.caption.decorationColor, + ); + + return Padding( + padding: const EdgeInsets.all(14.0), + child: Column( + children: [ + MarketPlaceItem( + onTap: () {}, + title: S.of(context).setup_your_debit_card, + subTitle: S.of(context).no_id_required, + ), + SizedBox(height: 48), + Container( + padding: EdgeInsets.only(left: 2, right: 22), + height: 32, + child: Row( + children: [ + Expanded(child: _SearchWidget()), + SizedBox(width: 10), + Container( + width: 32, + padding: EdgeInsets.all(8), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.15), + border: Border.all( + color: Colors.white.withOpacity(0.2), + ), + borderRadius: BorderRadius.circular(10), + ), + child: filterIcon, + ) + ], + ), + ), + SizedBox(height: 8), + Expanded( + child: RawScrollbar( + thumbColor: Colors.white.withOpacity(0.15), + radius: Radius.circular(20), + isAlwaysShown: true, + thickness: 2, + controller: _scrollController, + child: ListView.separated( + padding: EdgeInsets.only(left: 2, right: 22), + controller: _scrollController, + itemCount: 20, + separatorBuilder: (_, __) => SizedBox(height: 4), + itemBuilder: (_, index) { + return MarketPlaceItem( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 12), + logoUrl: '', + onTap: ()=>Navigator.of(context).pushNamed(Routes.buyGiftCardPage), + title: 'Amazon', + subTitle: 'Online', + hasDiscount: true, + ); + }, + ), + ), + ), + ], + ), + ); + } +} + +class _SearchWidget extends StatelessWidget { + const _SearchWidget({ + Key key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final searchIcon = Padding( + padding: EdgeInsets.all(8), + child: Image.asset( + 'assets/images/search_icon.png', + color: Theme.of(context).textTheme.caption.decorationColor, + ), + ); + + return TextField( + style: TextStyle(color: Colors.white), + decoration: InputDecoration( + filled: true, + contentPadding: EdgeInsets.only( + top: 10, + left: 10, + ), + fillColor: Colors.white.withOpacity(0.15), + hintText: 'Search', + hintStyle: TextStyle( + color: Colors.white.withOpacity(0.6), + ), + alignLabelWithHint: true, + floatingLabelBehavior: FloatingLabelBehavior.never, + suffixIcon: searchIcon, + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white.withOpacity(0.2), + ), + borderRadius: BorderRadius.circular(10), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.white.withOpacity(0.2), + ), + borderRadius: BorderRadius.circular(10), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.white.withOpacity(0.2)), + borderRadius: BorderRadius.circular(10), + )), + ); + } +} + +class _TrailingIcon extends StatelessWidget { + final String asset; + final VoidCallback onPressed; + + const _TrailingIcon({this.asset, this.onPressed}); + + @override + Widget build(BuildContext context) { + return Container( + alignment: Alignment.centerRight, + width: 25, + child: FlatButton( + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + padding: EdgeInsets.all(0), + onPressed: onPressed, + child: Image.asset( + asset, + color: Theme.of(context).accentTextTheme.display3.backgroundColor, + ), + ), + ); + } +} diff --git a/lib/src/screens/cake_pay/widgets/card_menu.dart b/lib/src/screens/cake_pay/widgets/card_menu.dart new file mode 100644 index 000000000..9212c0448 --- /dev/null +++ b/lib/src/screens/cake_pay/widgets/card_menu.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; + +class CardMenu extends StatelessWidget { + + @override + Widget build(BuildContext context) { + return Container( + + ); + } +} \ No newline at end of file diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index eb8c9ab17..f11398564 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -1,8 +1,8 @@ import 'dart:async'; +import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart'; import 'package:cw_core/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/screens/yat_emoji_id.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/themes/theme_base.dart'; @@ -14,19 +14,15 @@ import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/action_button.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart'; -import 'package:cake_wallet/src/screens/dashboard/widgets/address_page.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; import 'package:smooth_page_indicator/smooth_page_indicator.dart'; -import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:cake_wallet/main.dart'; -import 'package:cake_wallet/router.dart'; import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:cake_wallet/wallet_type_utils.dart'; class DashboardPage extends BasePage { DashboardPage({ @@ -85,7 +81,7 @@ class DashboardPage extends BasePage { final DashboardViewModel walletViewModel; final WalletAddressListViewModel addressListViewModel; - final controller = PageController(initialPage: 0); + final controller = PageController(initialPage: 1); var pages = []; bool _isEffectsInstalled = false; @@ -221,7 +217,7 @@ class DashboardPage extends BasePage { if (_isEffectsInstalled) { return; } - + pages.add(MarketPlacePage()); pages.add(balancePage); pages.add(TransactionsPage(dashboardViewModel: walletViewModel)); _isEffectsInstalled = true; diff --git a/lib/src/screens/dashboard/widgets/market_place_page.dart b/lib/src/screens/dashboard/widgets/market_place_page.dart new file mode 100644 index 000000000..cd67eb20d --- /dev/null +++ b/lib/src/screens/dashboard/widgets/market_place_page.dart @@ -0,0 +1,51 @@ +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/widgets/market_place_item.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/generated/i18n.dart'; + +class MarketPlacePage extends StatelessWidget { + final ScrollController _scrollController = ScrollController(); + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: RawScrollbar( + thumbColor: Colors.white.withOpacity(0.15), + radius: Radius.circular(20), + isAlwaysShown: true, + thickness: 2, + controller: _scrollController, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 50), + Text( + S.of(context).market_place, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w500, + color: Theme.of(context).accentTextTheme.display3.backgroundColor, + ), + ), + Expanded( + child: ListView( + controller: _scrollController, + children: [ + SizedBox(height: 20), + MarketPlaceItem( + onTap: () => Navigator.of(context).pushNamed(Routes.manageCardsPage), + title: S.of(context).cake_pay_title, + subTitle: S.of(context).cake_pay_subtitle, + ), + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/widgets/market_place_item.dart b/lib/src/widgets/market_place_item.dart new file mode 100644 index 000000000..ed3b90a4e --- /dev/null +++ b/lib/src/widgets/market_place_item.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'package:cached_network_image/cached_network_image.dart'; + +class MarketPlaceItem extends StatelessWidget { + final VoidCallback onTap; + final String title; + final String subTitle; + final String logoUrl; + final EdgeInsets padding; + final bool hasDiscount; + + MarketPlaceItem({ + @required this.onTap, + @required this.title, + @required this.subTitle, + this.logoUrl, + this.padding, + this.hasDiscount = false, + }); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: onTap, + child: Stack( + children: [ + Container( + padding: padding ?? EdgeInsets.all(20), + width: double.infinity, + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.20), + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Colors.white.withOpacity(0.20), + ), + ), + child: Row( + children: [ + if (logoUrl != null) ...[ + ClipOval( + child: CachedNetworkImage( + width: 42.0, + height: 42.0, + imageUrl: logoUrl, + placeholder: (context, url) => _PlaceholderContainer(text: 'Logo'), + errorWidget: (context, url, error) => _PlaceholderContainer(text: '!'), + ), + ), + SizedBox(width: 5), + ], + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.w900, + ), + ), + SizedBox(height: 5), + Text( + subTitle, + style: TextStyle( + color: Colors.white, + ), + ) + ], + ), + ], + ), + ), + if (hasDiscount) ...[ + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.only(top: 20.0), + child: Image.asset('assets/images/badge_discount.png'), + ), + ), + Align( + alignment: Alignment.centerRight, + child: Padding( + padding: const EdgeInsets.only(top: 22.0, right: 2), + child: Text( + 'Save 20%', + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.w500, + fontFamily: 'Lato', + ), + ), + ), + ) + ], + ], + ), + ); + } +} + +class _PlaceholderContainer extends StatelessWidget { + final String text; + + const _PlaceholderContainer({@required this.text}); + + @override + Widget build(BuildContext context) { + return Container( + height: 42, + width: 42, + child: Center( + child: Text( + text, + style: TextStyle( + color: Colors.black, + fontSize: 12, + fontWeight: FontWeight.w900, + ), + ), + ), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(100), + ), + ); + } +} diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 2de02e8b8..7366e0a62 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -527,5 +527,21 @@ "learn_more" : "Learn More", "search": "Search", "new_template" : "New Template", - "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work" + "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work", + "market_place": "Market place", + "cake_pay_title": "Gift cards and debit cards", + "cake_pay_subtitle": "Buy gift cards and top up no-KYC debit cards", + "about_cake_pay": "CakePay allows you to easily buy gift cards and load up prepaid debit cards with cryptocurrencies, spendable at millions of merchants in the United States.", + "cake_pay_account_note": "Make an account to see the available cards. Some are even available at a discount!", + "already_have_account": "Already have an account?", + "create_account": "Create Account", + "privacy_policy": "Privacy policy", + "welcome_to_cakepay": "Welcome to CakePay!", + "sign_up": "Sign Up", + "forgot_password": "Forgot Password", + "reset_password": "Reset Password", + "manage_cards": "Manage Cards", + "setup_your_debit_card": "Set up your debit card", + "no_id_required": "No ID required. Top up and spend anywhere", + "how_to_use_card": "How to use this card" } \ No newline at end of file