mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-20 06:08:34 +02:00
feat: Enable NFTs for Solana wallet (#2082)
* feat: Enable NFTs for Solana wallet * Add localization for texts * Adjust file naming * Adjust file naming
This commit is contained in:
@@ -23,13 +23,13 @@ class BalancePage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
final isEVMCompatible = isEVMCompatibleChain(dashboardViewModel.type);
|
||||
final isNFTActivated = isNFTACtivatedChain(dashboardViewModel.type);
|
||||
return DefaultTabController(
|
||||
key: ValueKey<bool>(isEVMCompatible),
|
||||
length: isEVMCompatible ? 2 : 1,
|
||||
key: ValueKey<bool>(isNFTActivated),
|
||||
length: isNFTActivated ? 2 : 1,
|
||||
child: Column(
|
||||
children: [
|
||||
if (isEVMCompatible)
|
||||
if (isNFTActivated)
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
@@ -76,7 +76,7 @@ class BalancePage extends StatelessWidget {
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
|
||||
if (isEVMCompatible) NFTListingPage(nftViewModel: nftViewModel)
|
||||
if (isNFTActivated) NFTListingPage(nftViewModel: nftViewModel)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/entities/solana_nft_asset_model.dart';
|
||||
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';
|
||||
@@ -8,21 +10,23 @@ 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});
|
||||
NFTDetailsPage({
|
||||
required this.dashboardViewModel,
|
||||
required this.arguments,
|
||||
Key? key,
|
||||
});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final NFTAssetModel nftAsset;
|
||||
final NFTDetailsPageArguments arguments;
|
||||
|
||||
@override
|
||||
bool get gradientBackground => true;
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||
(BuildContext context, Widget scaffold) =>
|
||||
GradientBackground(scaffold: scaffold);
|
||||
(BuildContext context, Widget scaffold) => GradientBackground(scaffold: scaffold);
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
@@ -30,15 +34,14 @@ class NFTDetailsPage extends BasePage {
|
||||
@override
|
||||
Widget get endDrawer => MenuWidget(
|
||||
dashboardViewModel,
|
||||
ValueKey('nft_details_page_menu_widget_key'),
|
||||
const ValueKey('nft_details_page_menu_widget_key'),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) {
|
||||
final menuButton = Image.asset(
|
||||
'assets/images/menu.png',
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
);
|
||||
|
||||
return Container(
|
||||
@@ -58,119 +61,200 @@ class NFTDetailsPage extends BasePage {
|
||||
@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: CakeImageWidget(
|
||||
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: S.current.description,
|
||||
infoValue: nftAsset.normalizedMetadata?.description ?? '---',
|
||||
),
|
||||
],
|
||||
|
||||
SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.contractName,
|
||||
infoValue: nftAsset.name ?? '---',
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.contractSymbol,
|
||||
infoValue: nftAsset.symbol ?? '---',
|
||||
),
|
||||
],
|
||||
),
|
||||
child: 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: arguments.isSolanaNFT
|
||||
? SolanaNFTDetailsWidget(
|
||||
solanaNftAsset: arguments.solanaNFTAssetModel,
|
||||
)
|
||||
: EVMChainNFTDetailsWidget(
|
||||
nftAsset: arguments.nftAsset,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NFTImageWidget extends StatelessWidget {
|
||||
final String? imageUrl;
|
||||
|
||||
const _NFTImageWidget({Key? key, this.imageUrl}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final balanceTheme = Theme.of(context).extension<BalancePageTheme>()!;
|
||||
final syncTheme = Theme.of(context).extension<SyncIndicatorTheme>()!;
|
||||
|
||||
return Container(
|
||||
height: MediaQuery.sizeOf(context).height / 2.5,
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.all(8),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
border: Border.all(
|
||||
color: balanceTheme.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: syncTheme.syncedBackgroundColor,
|
||||
),
|
||||
child: CakeImageWidget(imageUrl: imageUrl),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EVMChainNFTDetailsWidget extends StatelessWidget {
|
||||
final NFTAssetModel? nftAsset;
|
||||
|
||||
const EVMChainNFTDetailsWidget({Key? key, this.nftAsset}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (nftAsset == null) {
|
||||
return Center(child: Text(S.current.no_extra_detail));
|
||||
}
|
||||
|
||||
final metadata = nftAsset!.normalizedMetadata;
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_NFTImageWidget(imageUrl: metadata?.imageUrl),
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.name,
|
||||
infoValue: metadata?.name ?? '---',
|
||||
),
|
||||
if (metadata?.description != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.description,
|
||||
infoValue: metadata!.description ?? '---',
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.contractName,
|
||||
infoValue: nftAsset!.name ?? '---',
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.contractSymbol,
|
||||
infoValue: nftAsset!.symbol ?? '---',
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class SolanaNFTDetailsWidget extends StatelessWidget {
|
||||
final SolanaNFTAssetModel? solanaNftAsset;
|
||||
|
||||
const SolanaNFTDetailsWidget({Key? key, this.solanaNftAsset}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (solanaNftAsset == null) {
|
||||
return Center(child: Text(S.current.no_extra_detail));
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_NFTImageWidget(imageUrl: solanaNftAsset?.imageOriginalUrl),
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.name,
|
||||
infoValue: solanaNftAsset?.name ?? '---',
|
||||
),
|
||||
if (solanaNftAsset?.description != null) ...[
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.description,
|
||||
infoValue: solanaNftAsset!.description ?? '---',
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.mint_address,
|
||||
infoValue: solanaNftAsset?.mint ?? '---',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.contractName,
|
||||
infoValue: solanaNftAsset?.contract?.name ?? '---',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.contractSymbol,
|
||||
infoValue: solanaNftAsset?.contract?.symbol ?? '---',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.collection_name,
|
||||
infoValue: solanaNftAsset?.collection?.name ?? '---',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.collection_description,
|
||||
infoValue: solanaNftAsset?.collection?.description ?? '---',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_NFTSingleInfoTile(
|
||||
infoType: S.current.collection_address,
|
||||
infoValue: solanaNftAsset?.collection?.collectionAddress ?? '---',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _NFTSingleInfoTile extends StatelessWidget {
|
||||
final String infoType;
|
||||
final String infoValue;
|
||||
|
||||
const _NFTSingleInfoTile({
|
||||
required this.infoType,
|
||||
required this.infoValue,
|
||||
});
|
||||
|
||||
final String infoType;
|
||||
final String infoValue;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final balanceTheme = Theme.of(context).extension<BalancePageTheme>()!;
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
infoType,
|
||||
infoType,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor,
|
||||
color: balanceTheme.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
infoValue,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
color: balanceTheme.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
@@ -179,3 +263,15 @@ infoType,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NFTDetailsPageArguments {
|
||||
NFTDetailsPageArguments({
|
||||
this.nftAsset,
|
||||
this.solanaNFTAssetModel,
|
||||
required this.isSolanaNFT,
|
||||
});
|
||||
|
||||
final NFTAssetModel? nftAsset;
|
||||
final SolanaNFTAssetModel? solanaNFTAssetModel;
|
||||
final bool isSolanaNFT;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ 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:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
@@ -68,7 +69,6 @@ class _ImportNFTPage extends BasePage {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
|
||||
Text(
|
||||
S.current.address,
|
||||
textAlign: TextAlign.center,
|
||||
@@ -76,8 +76,7 @@ class _ImportNFTPage extends BasePage {
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w800,
|
||||
color:
|
||||
Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
|
||||
color: Theme.of(context).extension<SeedWidgetTheme>()!.hintTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
@@ -92,9 +91,7 @@ class _ImportNFTPage extends BasePage {
|
||||
tokenAddressController.text = tokenAddress;
|
||||
}
|
||||
},
|
||||
borderColor: Theme.of(context)
|
||||
.extension<CakeTextTheme>()!
|
||||
.textfieldUnderlineColor,
|
||||
borderColor: Theme.of(context).extension<CakeTextTheme>()!.textfieldUnderlineColor,
|
||||
iconColor: Theme.of(context).primaryColor,
|
||||
placeholder: '0x...',
|
||||
textStyle: TextStyle(
|
||||
@@ -108,46 +105,45 @@ class _ImportNFTPage extends BasePage {
|
||||
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,
|
||||
if (nftViewModel.appStore.wallet!.type != WalletType.solana) ...[
|
||||
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 ?? '';
|
||||
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,
|
||||
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,
|
||||
),
|
||||
),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: PaletteDark.darkCyanBlue,
|
||||
),
|
||||
),
|
||||
],
|
||||
Spacer(),
|
||||
Observer(builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
@@ -161,6 +157,7 @@ class _ImportNFTPage extends BasePage {
|
||||
},
|
||||
);
|
||||
}),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,32 +1,37 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
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/screens/dashboard/widgets/solana_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';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class NFTListingPage extends StatelessWidget {
|
||||
final NFTViewModel nftViewModel;
|
||||
|
||||
const NFTListingPage({super.key, required this.nftViewModel});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final dashboardTheme = Theme.of(context).extension<DashboardPageTheme>()!;
|
||||
final syncIndicatorTheme = Theme.of(context).extension<SyncIndicatorTheme>()!;
|
||||
final exchangeTheme = Theme.of(context).extension<ExchangePageTheme>()!;
|
||||
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
const SizedBox(height: 16),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 16, right: 16, bottom: 16),
|
||||
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16),
|
||||
child: PrimaryButton(
|
||||
text: S.current.import,
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.syncedBackgroundColor,
|
||||
color: syncIndicatorTheme.syncedBackgroundColor,
|
||||
textColor: Colors.white,
|
||||
onPressed: () => Navigator.pushNamed(
|
||||
context,
|
||||
@@ -39,46 +44,75 @@ class NFTListingPage extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(
|
||||
backgroundColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
backgroundColor: dashboardTheme.textColor,
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.firstGradientBottomPanelColor,
|
||||
exchangeTheme.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);
|
||||
},
|
||||
),
|
||||
)
|
||||
else
|
||||
Expanded(
|
||||
child: NFTListWidget(nftViewModel: nftViewModel),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NFTListWidget extends StatelessWidget {
|
||||
const NFTListWidget({required this.nftViewModel, super.key});
|
||||
|
||||
final NFTViewModel nftViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
final isSolana = nftViewModel.appStore.wallet!.type == WalletType.solana;
|
||||
|
||||
final emptyMessage = 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,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if (isSolana) {
|
||||
if (nftViewModel.solanaNftAssetModels.isEmpty) return emptyMessage;
|
||||
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 16),
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 8),
|
||||
itemCount: nftViewModel.solanaNftAssetModels.length,
|
||||
itemBuilder: (context, index) {
|
||||
final nftAsset = nftViewModel.solanaNftAssetModels[index];
|
||||
return SolanaNFTTileWidget(nftAsset: nftAsset);
|
||||
},
|
||||
);
|
||||
} else {
|
||||
if (nftViewModel.nftAssetByWalletModels.isEmpty) return emptyMessage;
|
||||
|
||||
return ListView.separated(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 16),
|
||||
separatorBuilder: (context, index) => const SizedBox(height: 8),
|
||||
itemCount: nftViewModel.nftAssetByWalletModels.length,
|
||||
itemBuilder: (context, index) {
|
||||
final nftAsset = nftViewModel.nftAssetByWalletModels[index];
|
||||
return NFTTileWidget(nftAsset: nftAsset);
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:cake_wallet/entities/wallet_nft_response.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_details_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
@@ -12,7 +13,14 @@ class NFTTileWidget extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
onTap: () => Navigator.pushNamed(context, Routes.nftDetailsPage, arguments: nftAsset),
|
||||
onTap: () => Navigator.pushNamed(
|
||||
context,
|
||||
Routes.nftDetailsPage,
|
||||
arguments: NFTDetailsPageArguments(
|
||||
isSolanaNFT: false,
|
||||
nftAsset: nftAsset,
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.only(left: 16, right: 16),
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/entities/solana_nft_asset_model.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_details_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
|
||||
class SolanaNFTTileWidget extends StatelessWidget {
|
||||
const SolanaNFTTileWidget({super.key, required this.nftAsset});
|
||||
|
||||
final SolanaNFTAssetModel nftAsset;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final balanceTheme = Theme.of(context).extension<BalancePageTheme>()!;
|
||||
final syncTheme = Theme.of(context).extension<SyncIndicatorTheme>()!;
|
||||
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.nftDetailsPage,
|
||||
arguments: NFTDetailsPageArguments(
|
||||
isSolanaNFT: true,
|
||||
solanaNFTAssetModel: nftAsset,
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 16),
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
border: Border.all(
|
||||
color: balanceTheme.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: syncTheme.syncedBackgroundColor,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
height: 100,
|
||||
width: 100,
|
||||
margin: const EdgeInsets.all(8),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(16.0),
|
||||
border: Border.all(
|
||||
color: balanceTheme.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: syncTheme.syncedBackgroundColor,
|
||||
),
|
||||
child: CakeImageWidget(
|
||||
imageUrl: nftAsset.imageOriginalUrl,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Symbol: ${nftAsset.symbol ?? '---'}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: balanceTheme.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
(nftAsset.name?.isNotEmpty ?? false)
|
||||
? nftAsset.name!
|
||||
: (nftAsset.symbol ?? '---'),
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w900,
|
||||
color: balanceTheme.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user