Merge branch 'main' into CW-529-Modify-2FA-introduction-screens

This commit is contained in:
Serhii
2023-11-24 07:53:20 +02:00
51 changed files with 1215 additions and 127 deletions
@@ -1,11 +1,10 @@
import 'dart:async';
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/main_actions.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
@@ -15,7 +14,6 @@ import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.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/utils/responsive_layout_util.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
@@ -23,8 +21,8 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
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/transactions_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/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';
@@ -1,17 +1,14 @@
import 'dart:async';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.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/utils/show_pop_up.dart';
import 'package:cake_wallet/utils/version_comparator.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/balance_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/router.dart' as Router;
import 'package:shared_preferences/shared_preferences.dart';
@@ -1,7 +1,7 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/main_actions.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_action_button.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
import 'package:flutter/material.dart';
@@ -6,10 +6,8 @@ import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/entities/receive_page_option.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
@@ -26,7 +24,6 @@ import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:keyboard_actions/keyboard_actions.dart';
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
class AddressPage extends BasePage {
@@ -163,8 +160,7 @@ class AddressPage extends BasePage {
return GestureDetector(
onTap: () async => dashboardViewModel.isAutoGenerateSubaddressesEnabled
? await showPopUp<void>(
context: context,
builder: (_) => getIt.get<MoneroAccountListPage>())
context: context, builder: (_) => getIt.get<MoneroAccountListPage>())
: Navigator.of(context).pushNamed(Routes.receive),
child: Container(
height: 50,
@@ -184,26 +180,27 @@ class AddressPage extends BasePage {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Observer(
builder: (_) {
String label = addressListViewModel.hasAccounts
? S.of(context).accounts_subaddresses
: S.of(context).addresses;
builder: (_) {
String label = addressListViewModel.hasAccounts
? S.of(context).accounts_subaddresses
: S.of(context).addresses;
if (dashboardViewModel.isAutoGenerateSubaddressesEnabled) {
label = addressListViewModel.hasAccounts
? S.of(context).accounts
: S.of(context).account;
}
return Text(
label,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context)
.extension<SyncIndicatorTheme>()!
.textColor),
);
},),
if (dashboardViewModel.isAutoGenerateSubaddressesEnabled) {
label = addressListViewModel.hasAccounts
? S.of(context).accounts
: S.of(context).account;
}
return Text(
label,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context)
.extension<SyncIndicatorTheme>()!
.textColor),
);
},
),
Icon(
Icons.arrow_forward_ios,
size: 14,
@@ -213,7 +210,8 @@ class AddressPage extends BasePage {
),
),
);
} else if (dashboardViewModel.isAutoGenerateSubaddressesEnabled || addressListViewModel.showElectrumAddressDisclaimer) {
} else if (dashboardViewModel.isAutoGenerateSubaddressesEnabled ||
addressListViewModel.showElectrumAddressDisclaimer) {
return Text(S.of(context).electrum_address_disclaimer,
textAlign: TextAlign.center,
style: TextStyle(
@@ -1,6 +1,7 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
import 'package:cake_wallet/src/widgets/introducing_card.dart';
@@ -11,15 +12,80 @@ import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class BalancePage extends StatelessWidget {
BalancePage({required this.dashboardViewModel, required this.settingsStore});
BalancePage({
required this.dashboardViewModel,
required this.settingsStore,
required this.nftViewModel,
});
final DashboardViewModel dashboardViewModel;
final NFTViewModel nftViewModel;
final SettingsStore settingsStore;
@override
Widget build(BuildContext context) {
return Observer(
builder: (context) {
final isEthereumWallet = dashboardViewModel.type == WalletType.ethereum;
return DefaultTabController(
length: isEthereumWallet ? 2 : 1,
child: Column(
children: [
if (isEthereumWallet)
Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.only(left: 8),
child: TabBar(
indicatorSize: TabBarIndicatorSize.label,
isScrollable: true,
physics: NeverScrollableScrollPhysics(),
labelStyle: TextStyle(
fontSize: 18,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
height: 1,
),
tabs: [
Tab(text: 'My Crypto'),
Tab(text: 'My NFTs'),
],
),
),
),
Expanded(
child: TabBarView(
physics: NeverScrollableScrollPhysics(),
children: [
CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
if (isEthereumWallet) NFTListingPage(nftViewModel: nftViewModel)
],
),
),
],
),
);
},
);
}
}
class CryptoBalanceWidget extends StatelessWidget {
const CryptoBalanceWidget({
super.key,
required this.dashboardViewModel,
});
final DashboardViewModel dashboardViewModel;
@override
Widget build(BuildContext context) {
return GestureDetector(
@@ -38,7 +104,7 @@ class BalancePage extends StatelessWidget {
accountName: dashboardViewModel.subname)
: Column(
children: [
SizedBox(height: 56),
SizedBox(height: 16),
Container(
margin: const EdgeInsets.only(left: 24, bottom: 16),
child: Observer(
@@ -105,8 +171,7 @@ class BalancePage extends StatelessWidget {
itemBuilder: (__, index) {
final balance =
dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
return buildBalanceRow(
context,
return BalanceRowWidget(
availableBalanceLabel:
'${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
availableBalance: balance.availableBalance,
@@ -130,20 +195,44 @@ class BalancePage extends StatelessWidget {
),
);
}
}
Widget buildBalanceRow(
BuildContext context, {
required String availableBalanceLabel,
required String availableBalance,
required String availableFiatBalance,
required String additionalBalanceLabel,
required String additionalBalance,
required String additionalFiatBalance,
required String frozenBalance,
required String frozenFiatBalance,
required String currency,
required bool hasAdditionalBalance,
}) {
class BalanceRowWidget extends StatelessWidget {
const BalanceRowWidget({
required this.availableBalanceLabel,
required this.availableBalance,
required this.availableFiatBalance,
required this.additionalBalanceLabel,
required this.additionalBalance,
required this.additionalFiatBalance,
required this.frozenBalance,
required this.frozenFiatBalance,
required this.currency,
required this.hasAdditionalBalance,
super.key,
});
final String availableBalanceLabel;
final String availableBalance;
final String availableFiatBalance;
final String additionalBalanceLabel;
final String additionalBalance;
final String additionalFiatBalance;
final String frozenBalance;
final String frozenFiatBalance;
final String currency;
final bool hasAdditionalBalance;
// void _showBalanceDescription(BuildContext context) {
// showPopUp<void>(
// context: context,
// builder: (_) =>
// InformationPage(information: S.current.available_balance_description),
// );
// }
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.only(left: 16, right: 16),
decoration: BoxDecoration(
@@ -165,8 +254,9 @@ class BalancePage extends StatelessWidget {
children: [
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: hasAdditionalBalance ? () =>
_showBalanceDescription(context, S.current.available_balance_description)
onTap: hasAdditionalBalance
? () =>
_showBalanceDescription(context, S.current.available_balance_description)
: null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -229,8 +319,9 @@ class BalancePage extends StatelessWidget {
if (frozenBalance.isNotEmpty)
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: hasAdditionalBalance ?
() => _showBalanceDescription(context, S.current.unavailable_balance_description)
onTap: hasAdditionalBalance
? () =>
_showBalanceDescription(context, S.current.unavailable_balance_description)
: null,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -253,9 +344,8 @@ class BalancePage extends StatelessWidget {
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Icon(Icons.help_outline,
size: 16,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor),
color:
Theme.of(context).extension<BalancePageTheme>()!.labelTextColor),
),
],
),
@@ -337,8 +427,6 @@ class BalancePage extends StatelessWidget {
}
void _showBalanceDescription(BuildContext context, String content) {
showPopUp<void>(
context: context,
builder: (_) => InformationPage(information: content));
showPopUp<void>(context: context, builder: (_) => InformationPage(information: content));
}
}
@@ -0,0 +1,178 @@
import 'package:cake_wallet/entities/wallet_nft_response.dart';
import 'package:cake_wallet/generated/i18n.dart';
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/nft_image_tile_widget.dart';
import 'package:cake_wallet/src/widgets/gradient_background.dart';
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:flutter/material.dart';
class NFTDetailsPage extends BasePage {
NFTDetailsPage({required this.dashboardViewModel, required this.nftAsset});
final DashboardViewModel dashboardViewModel;
final NFTAssetModel nftAsset;
@override
bool get gradientBackground => true;
@override
Widget Function(BuildContext, Widget) get rootWrapper =>
(BuildContext context, Widget scaffold) =>
GradientBackground(scaffold: scaffold);
@override
bool get resizeToAvoidBottomInset => false;
@override
Widget get endDrawer => MenuWidget(dashboardViewModel);
@override
Widget trailing(BuildContext context) {
final menuButton = Image.asset(
'assets/images/menu.png',
color:
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
);
return Container(
alignment: Alignment.centerRight,
width: 40,
child: TextButton(
// FIX-ME: Style
//highlightColor: Colors.transparent,
//splashColor: Colors.transparent,
//padding: EdgeInsets.all(0),
onPressed: () => onOpenEndDrawer(),
child: Semantics(label: S.of(context).wallet_menu, child: menuButton),
),
);
}
@override
Widget body(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: [
Container(
width: double.infinity,
margin: const EdgeInsets.all(16),
padding: const EdgeInsets.symmetric(vertical: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
border: Border.all(
color: Theme.of(context)
.extension<BalancePageTheme>()!
.cardBorderColor,
width: 1,
),
color: Theme.of(context)
.extension<SyncIndicatorTheme>()!
.syncedBackgroundColor,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: MediaQuery.sizeOf(context).height / 2.5,
width: double.infinity,
clipBehavior: Clip.hardEdge,
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: Theme.of(context)
.extension<BalancePageTheme>()!
.cardBorderColor,
width: 1,
),
color: Theme.of(context)
.extension<SyncIndicatorTheme>()!
.syncedBackgroundColor,
),
child: NFTImageWidget(
imageUrl: nftAsset.normalizedMetadata?.imageUrl,
),
),
SizedBox(height: 16),
_NFTSingleInfoTile(
infoType: S.current.name,
infoValue: nftAsset.normalizedMetadata?.name ?? '',
),
if (nftAsset.normalizedMetadata?.description != null) ...[
SizedBox(height: 16),
_NFTSingleInfoTile(
infoType: 'Description',
infoValue: nftAsset.normalizedMetadata?.description ?? '',
),
],
SizedBox(height: 16),
_NFTSingleInfoTile(
infoType: 'Contract Name',
infoValue: nftAsset.name ?? '',
),
SizedBox(height: 8),
_NFTSingleInfoTile(
infoType: 'Contract Symbol',
infoValue: nftAsset.symbol ?? '',
),
],
),
),
],
),
);
}
}
class _NFTSingleInfoTile extends StatelessWidget {
const _NFTSingleInfoTile({
required this.infoType,
required this.infoValue,
});
final String infoType;
final String infoValue;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
infoType,
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
SizedBox(height: 8),
Text(
infoValue,
style: TextStyle(
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
),
],
),
);
}
}
@@ -0,0 +1,168 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/address_text_field.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/seed_widget_theme.dart';
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class ImportNFTPage extends StatefulWidget {
const ImportNFTPage({required this.nftViewModel, super.key});
final NFTViewModel nftViewModel;
@override
State<ImportNFTPage> createState() => _ImportNFTPageState();
}
class _ImportNFTPageState extends State<ImportNFTPage> {
late TextEditingController tokenAddressController;
late TextEditingController tokenIDController;
@override
void initState() {
super.initState();
tokenAddressController = TextEditingController();
tokenIDController = TextEditingController();
}
@override
void dispose() {
tokenAddressController.dispose();
tokenIDController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return _ImportNFTPage(
nftViewModel: widget.nftViewModel,
tokenAddressController: tokenAddressController,
tokenIDController: tokenIDController,
);
}
}
class _ImportNFTPage extends BasePage {
_ImportNFTPage({
required this.tokenIDController,
required this.tokenAddressController,
required this.nftViewModel,
});
final NFTViewModel nftViewModel;
final TextEditingController tokenIDController;
final TextEditingController tokenAddressController;
@override
String? get title => S.current.import;
@override
Widget body(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
S.current.address,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.w800,
color:
Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
height: 1,
),
),
AddressTextField(
controller: tokenAddressController,
options: [AddressTextFieldOption.paste],
onPushPasteButton: (context) async {
final clipboard = await Clipboard.getData('text/plain');
final tokenAddress = clipboard?.text ?? '';
if (tokenAddress.isNotEmpty) {
tokenAddressController.text = tokenAddress;
}
},
borderColor: Theme.of(context)
.extension<CakeTextTheme>()!
.textfieldUnderlineColor,
iconColor: Theme.of(context).primaryColor,
placeholder: '0x...',
textStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.darkCyanBlue,
),
hintStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.darkCyanBlue,
),
),
SizedBox(height: 48),
Text(
S.current.tokenID,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
fontFamily: 'Lato',
fontWeight: FontWeight.w800,
color: Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
height: 1,
),
),
AddressTextField(
controller: tokenIDController,
options: [AddressTextFieldOption.paste],
onPushPasteButton: (context) async {
final clipboard = await Clipboard.getData('text/plain');
final tokenID = clipboard?.text ?? '';
if (tokenID.isNotEmpty) {
tokenIDController.text = tokenID;
}
},
borderColor: Theme.of(context)
.extension<CakeTextTheme>()!
.textfieldUnderlineColor,
iconColor: Theme.of(context).primaryColor,
placeholder: S.current.enterTokenID,
textStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.darkCyanBlue,
),
hintStyle: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: PaletteDark.darkCyanBlue,
),
),
Spacer(),
Observer(builder: (context) {
return LoadingPrimaryButton(
isLoading: nftViewModel.isImportNFTLoading,
text: S.current.import,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
onPressed: () async {
await nftViewModel.importNFT(tokenAddressController.text, tokenIDController.text);
Navigator.pop(context);
},
);
}),
],
),
);
}
}
@@ -0,0 +1,84 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/nft_tile_widget.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class NFTListingPage extends StatelessWidget {
final NFTViewModel nftViewModel;
const NFTListingPage({super.key, required this.nftViewModel});
@override
Widget build(BuildContext context) {
return Observer(
builder: (context) {
return Column(
children: [
SizedBox(height: 16),
Padding(
padding: EdgeInsets.only(left: 16, right: 16, bottom: 16),
child: PrimaryButton(
text: S.current.import,
color: Theme.of(context)
.extension<SyncIndicatorTheme>()!
.syncedBackgroundColor,
textColor: Colors.white,
onPressed: () => Navigator.pushNamed(
context,
Routes.importNFTPage,
arguments: nftViewModel,
),
),
),
if (nftViewModel.isLoading)
Expanded(
child: Center(
child: CircularProgressIndicator(
backgroundColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
valueColor: AlwaysStoppedAnimation<Color>(
Theme.of(context)
.extension<ExchangePageTheme>()!
.firstGradientBottomPanelColor,
),
),
),
),
if (!nftViewModel.isLoading)
Expanded(
child: nftViewModel.nftAssetByWalletModels.isEmpty
? Center(
child: Text(
S.current.noNFTYet,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context)
.extension<DashboardPageTheme>()!
.pageTitleTextColor,
height: 1,
),
),
)
: ListView.separated(
padding: EdgeInsets.symmetric(horizontal: 4, vertical: 16),
separatorBuilder: (context, index) => SizedBox(height: 8),
itemCount: nftViewModel.nftAssetByWalletModels.length,
itemBuilder: (context, index) {
final nftAsset = nftViewModel.nftAssetByWalletModels[index];
return NFTTileWidget(nftAsset: nftAsset);
},
),
)
],
);
},
);
}
}
@@ -46,9 +46,11 @@ class TransactionsPage extends StatelessWidget {
return Padding(
padding: const EdgeInsets.fromLTRB(24, 0, 24, 8),
child: DashBoardRoundedCardWidget(
onTap: () => Navigator.of(context).pushNamed(
Routes.webViewPage,
arguments: ['', Uri.parse('https://guides.cakewallet.com/docs/bugs-service-status/why_are_my_funds_not_appearing/')]),
onTap: () => Navigator.of(context).pushNamed(Routes.webViewPage, arguments: [
'',
Uri.parse(
'https://guides.cakewallet.com/docs/bugs-service-status/why_are_my_funds_not_appearing/')
]),
title: S.of(context).syncing_wallet_alert_title,
subTitle: S.of(context).syncing_wallet_alert_content,
),
@@ -76,40 +78,34 @@ class TransactionsPage extends StatelessWidget {
return Observer(
builder: (_) => TransactionRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.transactionDetails,
arguments: transaction),
onTap: () => Navigator.of(context)
.pushNamed(Routes.transactionDetails, arguments: transaction),
direction: transaction.direction,
formattedDate: DateFormat('HH:mm')
.format(transaction.date),
formattedDate: DateFormat('HH:mm').format(transaction.date),
formattedAmount: item.formattedCryptoAmount,
formattedFiatAmount: dashboardViewModel
.balanceViewModel.isFiatDisabled
? ''
: item.formattedFiatAmount,
formattedFiatAmount:
dashboardViewModel.balanceViewModel.isFiatDisabled
? ''
: item.formattedFiatAmount,
isPending: transaction.isPending,
title: item.formattedTitle +
item.formattedStatus));
title: item.formattedTitle + item.formattedStatus));
}
if (item is AnonpayTransactionListItem) {
final transactionInfo = item.transaction;
return AnonpayTransactionRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.anonPayDetailsPage,
arguments: transactionInfo),
onTap: () => Navigator.of(context)
.pushNamed(Routes.anonPayDetailsPage, arguments: transactionInfo),
currency: transactionInfo.fiatAmount != null
? transactionInfo.fiatEquiv ?? ''
: CryptoCurrency.fromFullName(
transactionInfo.coinTo)
: CryptoCurrency.fromFullName(transactionInfo.coinTo)
.name
.toUpperCase(),
provider: transactionInfo.provider,
amount: transactionInfo.fiatAmount?.toString() ??
(transactionInfo.amountTo?.toString() ?? ''),
createdAt: DateFormat('HH:mm')
.format(transactionInfo.createdAt),
createdAt: DateFormat('HH:mm').format(transactionInfo.createdAt),
);
}
@@ -118,17 +114,14 @@ class TransactionsPage extends StatelessWidget {
return Observer(
builder: (_) => TradeRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.tradeDetails,
arguments: trade),
onTap: () => Navigator.of(context)
.pushNamed(Routes.tradeDetails, arguments: trade),
provider: trade.provider,
from: trade.from,
to: trade.to,
createdAtFormattedDate:
trade.createdAt != null
? DateFormat('HH:mm')
.format(trade.createdAt!)
: null,
createdAtFormattedDate: trade.createdAt != null
? DateFormat('HH:mm').format(trade.createdAt!)
: null,
formattedAmount: item.tradeFormattedAmount));
}
@@ -138,13 +131,12 @@ class TransactionsPage extends StatelessWidget {
return Observer(
builder: (_) => OrderRow(
onTap: () => Navigator.of(context)
.pushNamed(Routes.orderDetails,
arguments: order),
.pushNamed(Routes.orderDetails, arguments: order),
provider: order.provider,
from: order.from!,
to: order.to!,
createdAtFormattedDate: DateFormat('HH:mm')
.format(order.createdAt),
createdAtFormattedDate:
DateFormat('HH:mm').format(order.createdAt),
formattedAmount: item.orderFormattedAmount,
));
}
@@ -0,0 +1,37 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
class NFTImageWidget extends StatelessWidget {
const NFTImageWidget({
required this.imageUrl,
});
final String? imageUrl;
@override
Widget build(BuildContext context) {
try {
if (imageUrl == null) return Icon(Icons.error);
if (imageUrl!.contains('.svg')) {
return SvgPicture.network(imageUrl!);
}
return Image.network(
imageUrl!,
fit: BoxFit.cover,
loadingBuilder: (BuildContext _, Widget child, ImageChunkEvent? loadingProgress) {
if (loadingProgress == null) {
return child;
} else {
return CupertinoActivityIndicator(animating: true);
}
},
errorBuilder: (_, __, ___) => Icon(Icons.error),
);
} catch (_) {
return Icon(Icons.error);
}
}
}
@@ -0,0 +1,95 @@
import 'package:cake_wallet/entities/wallet_nft_response.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/nft_image_tile_widget.dart';
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class NFTTileWidget extends StatelessWidget {
const NFTTileWidget({super.key, required this.nftAsset});
final NFTAssetModel nftAsset;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () => Navigator.pushNamed(context, Routes.nftDetailsPage,
arguments: nftAsset),
child: Container(
width: double.infinity,
margin: const EdgeInsets.only(left: 16, right: 16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
border: Border.all(
color: Theme.of(context)
.extension<BalancePageTheme>()!
.cardBorderColor,
width: 1,
),
color: Theme.of(context)
.extension<SyncIndicatorTheme>()!
.syncedBackgroundColor,
),
child: Row(
children: [
Container(
height: 100,
width: 100,
clipBehavior: Clip.hardEdge,
margin: const EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0),
border: Border.all(
color: Theme.of(context)
.extension<BalancePageTheme>()!
.cardBorderColor,
width: 1,
),
color: Theme.of(context)
.extension<SyncIndicatorTheme>()!
.syncedBackgroundColor,
),
child: NFTImageWidget(
imageUrl: nftAsset.normalizedMetadata?.imageUrl,
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${nftAsset.name ?? ''} - ${nftAsset.symbol ?? ''}',
style: TextStyle(
fontSize: 12,
fontFamily: 'Lato',
fontWeight: FontWeight.w400,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.labelTextColor,
height: 1,
),
),
SizedBox(height: 8),
Text(
nftAsset.normalizedMetadata?.name ?? nftAsset.name ?? "",
style: TextStyle(
fontSize: 20,
fontFamily: 'Lato',
fontWeight: FontWeight.w900,
color: Theme.of(context)
.extension<BalancePageTheme>()!
.assetTitleColor,
height: 1,
),
),
],
),
)
],
),
),
);
}
}
+3
View File
@@ -67,13 +67,16 @@ class AddressTextField extends StatelessWidget {
enabled: isActive,
controller: controller,
focusNode: focusNode,
style: textStyle ??
TextStyle(
fontSize: 16, color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
decoration: InputDecoration(
suffixIcon: SizedBox(
width: prefixIconWidth * options.length + (spaceBetweenPrefixIcons * options.length),
),
hintStyle: hintStyle ?? TextStyle(fontSize: 16, color: Theme.of(context).hintColor),
hintText: placeholder ?? S.current.widgets_address,
focusedBorder: isBorderExist