From 3cd05d0514178ae55dcc59b36b86dbf4ffb3a3aa Mon Sep 17 00:00:00 2001 From: Dominik Toton <166132265+dtscalac@users.noreply.github.com> Date: Thu, 12 Sep 2024 14:50:58 +0200 Subject: [PATCH] feat: funded projects space (#794) * fix: jumping images in favorite proposals * feat: add funded projects space --- .../funded_projects/funded_projects_page.dart | 179 +++++++++++++++++- .../lib/pages/voting/voting_page.dart | 19 +- .../widgets/cards/funded_proposal_card.dart | 2 +- .../lib/src/themes/catalyst.dart | 2 +- .../catalyst_voices_localizations.dart | 18 ++ .../catalyst_voices_localizations_en.dart | 11 ++ .../catalyst_voices_localizations_es.dart | 11 ++ .../lib/l10n/intl_en.arb | 17 ++ 8 files changed, 243 insertions(+), 16 deletions(-) diff --git a/catalyst_voices/lib/pages/funded_projects/funded_projects_page.dart b/catalyst_voices/lib/pages/funded_projects/funded_projects_page.dart index e4456300844..2c2826be39a 100644 --- a/catalyst_voices/lib/pages/funded_projects/funded_projects_page.dart +++ b/catalyst_voices/lib/pages/funded_projects/funded_projects_page.dart @@ -1,17 +1,184 @@ +import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart'; +import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; +import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:flutter/material.dart'; +final _proposalDescription = """ +Zanzibar is becoming one of the hotspots for DID's through +World Mobile and PRISM, but its potential is only barely exploited. +Zanzibar is becoming one of the hotspots for DID's through World Mobile +and PRISM, but its potential is only barely exploited. +""" + .replaceAll('\n', ' '); + +final _proposals = [ + FundedProposal( + id: 'f14/0', + fund: 'F14', + category: 'Cardano Use Cases / MVP', + title: 'Proposal Title that rocks the world', + fundedDate: DateTime.now().minusDays(2), + fundsRequested: Coin.fromAda(100000), + commentsCount: 0, + description: _proposalDescription, + ), + FundedProposal( + id: 'f14/1', + fund: 'F14', + category: 'Cardano Use Cases / MVP', + title: 'Proposal Title that rocks the world', + fundedDate: DateTime.now().minusDays(2), + fundsRequested: Coin.fromAda(100000), + commentsCount: 0, + description: _proposalDescription, + ), + FundedProposal( + id: 'f14/2', + fund: 'F14', + category: 'Cardano Use Cases / MVP', + title: 'Proposal Title that rocks the world', + fundedDate: DateTime.now().minusDays(2), + fundsRequested: Coin.fromAda(100000), + commentsCount: 0, + description: _proposalDescription, + ), +]; + +final _proposalImages = { + for (final (index, proposal) in _proposals.indexed) + proposal.id: index.isEven + ? VoicesAssets.images.proposalBackground1 + : VoicesAssets.images.proposalBackground2, +}; + +final _favoriteProposals = ValueNotifier>([]); + class FundedProjectsPage extends StatelessWidget { const FundedProjectsPage({super.key}); @override Widget build(BuildContext context) { - return Container( - color: Colors.deepOrangeAccent, - alignment: Alignment.center, - child: Text( - 'Funded Projects', - style: Theme.of(context).textTheme.titleLarge, + return ListView( + padding: const EdgeInsets.symmetric(horizontal: 32), + children: [ + const SizedBox(height: 44), + Text( + context.l10n.fundedProjectSpace, + style: Theme.of(context).textTheme.headlineLarge, + ), + const SizedBox(height: 44), + _Tabs(), + ], + ); + } +} + +class _Tabs extends StatelessWidget { + const _Tabs(); + + @override + Widget build(BuildContext context) { + return DefaultTabController( + length: 2, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TabBar( + isScrollable: true, + tabAlignment: TabAlignment.start, + tabs: [ + Tab( + text: context.l10n.noOfFundedProposals(_proposals.length), + ), + Tab( + child: Row( + children: [ + Icon(CatalystVoicesIcons.plus_circle), + const SizedBox(width: 8), + Text(context.l10n.followed), + ], + ), + ), + ], + ), + const SizedBox(height: 24), + TabBarStackView( + children: [ + _AllProposals(), + _FavoriteProposals(), + ], + ), + const SizedBox(height: 12), + ], ), ); } } + +class _AllProposals extends StatelessWidget { + const _AllProposals(); + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder>( + valueListenable: _favoriteProposals, + builder: (context, favoriteProposals, child) { + return Wrap( + spacing: 16, + runSpacing: 16, + children: [ + for (final proposal in _proposals) + FundedProposalCard( + image: _proposalImages[proposal.id]!, + proposal: proposal, + isFavorite: favoriteProposals.contains(proposal), + onFavoriteChanged: (isFavorite) => + _onFavoriteChanged(proposal, isFavorite), + ), + ], + ); + }, + ); + } +} + +class _FavoriteProposals extends StatelessWidget { + const _FavoriteProposals(); + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder>( + valueListenable: _favoriteProposals, + builder: (context, favoriteProposals, child) { + return Wrap( + spacing: 16, + runSpacing: 16, + children: [ + for (final proposal in favoriteProposals) + FundedProposalCard( + image: _proposalImages[proposal.id]!, + proposal: proposal, + isFavorite: true, + onFavoriteChanged: (isFavorite) => + _onFavoriteChanged(proposal, isFavorite), + ), + ], + ); + }, + ); + } +} + +void _onFavoriteChanged(FundedProposal proposal, bool isFavorite) { + final proposals = Set.of(_favoriteProposals.value); + if (isFavorite) { + proposals.add(proposal); + } else { + proposals.remove(proposal); + } + _favoriteProposals.value = proposals.toList(); +} diff --git a/catalyst_voices/lib/pages/voting/voting_page.dart b/catalyst_voices/lib/pages/voting/voting_page.dart index e9e68669de2..ff7cc90d666 100644 --- a/catalyst_voices/lib/pages/voting/voting_page.dart +++ b/catalyst_voices/lib/pages/voting/voting_page.dart @@ -54,6 +54,13 @@ final _proposals = [ ), ]; +final _proposalImages = { + for (final (index, proposal) in _proposals.indexed) + proposal.id: index.isEven + ? VoicesAssets.images.proposalBackground1 + : VoicesAssets.images.proposalBackground2, +}; + final _favoriteProposals = ValueNotifier>([]); class VotingPage extends StatelessWidget { @@ -131,11 +138,9 @@ class _AllProposals extends StatelessWidget { spacing: 16, runSpacing: 16, children: [ - for (final (index, proposal) in _proposals.indexed) + for (final proposal in _proposals) PendingProposalCard( - image: index.isEven - ? VoicesAssets.images.proposalBackground1 - : VoicesAssets.images.proposalBackground2, + image: _proposalImages[proposal.id]!, proposal: proposal, isFavorite: favoriteProposals.contains(proposal), onFavoriteChanged: (isFavorite) => @@ -160,11 +165,9 @@ class _FavoriteProposals extends StatelessWidget { spacing: 16, runSpacing: 16, children: [ - for (final (index, proposal) in favoriteProposals.indexed) + for (final proposal in favoriteProposals) PendingProposalCard( - image: index.isEven - ? VoicesAssets.images.proposalBackground1 - : VoicesAssets.images.proposalBackground2, + image: _proposalImages[proposal.id]!, proposal: proposal, isFavorite: true, onFavoriteChanged: (isFavorite) => diff --git a/catalyst_voices/lib/widgets/cards/funded_proposal_card.dart b/catalyst_voices/lib/widgets/cards/funded_proposal_card.dart index 46d6edd0b51..2352b9fb8f0 100644 --- a/catalyst_voices/lib/widgets/cards/funded_proposal_card.dart +++ b/catalyst_voices/lib/widgets/cards/funded_proposal_card.dart @@ -99,7 +99,7 @@ class _Header extends StatelessWidget { padding: EdgeInsets.zero, onPressed: () => onFavoriteChanged?.call(!isFavorite), icon: Icon( - isFavorite ? Icons.favorite : CatalystVoicesIcons.star, + isFavorite ? Icons.favorite : CatalystVoicesIcons.plus_circle, size: 20, color: Theme.of(context).colors.iconsOnImage, ), diff --git a/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/catalyst.dart b/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/catalyst.dart index e13e7950b3b..8c69a0324fb 100644 --- a/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/catalyst.dart +++ b/catalyst_voices/packages/catalyst_voices_brands/lib/src/themes/catalyst.dart @@ -132,7 +132,7 @@ const VoicesColorScheme lightVoicesColorScheme = VoicesColorScheme( onSurfaceError08: VoicesColors.lightOnSurfaceError08, onSurfaceError012: VoicesColors.lightOnSurfaceError012, onSurfaceError016: VoicesColors.lightOnSurfaceError016, - iconsForeground: Color.fromARGB(255, 151, 164, 193), + iconsForeground: VoicesColors.lightIconsForeground, iconsBackground: VoicesColors.lightIconsBackground, iconsOnImage: VoicesColors.lightIconsOnImage, iconsDisabled: VoicesColors.lightIconsDisabled, diff --git a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart index 603c478311d..62484792398 100644 --- a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart +++ b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations.dart @@ -477,6 +477,24 @@ abstract class VoicesLocalizations { /// In en, this message translates to: /// **'Funded projects'** String get drawerSpaceFundedProjects; + + /// Title of the funded project space + /// + /// In en, this message translates to: + /// **'Funded project space'** + String get fundedProjectSpace; + + /// Tab label for funded proposals in funded projects space + /// + /// In en, this message translates to: + /// **'Funded proposals ({count})'** + String noOfFundedProposals(int count); + + /// Refers to a list of followed items. + /// + /// In en, this message translates to: + /// **'Followed'** + String get followed; } class _VoicesLocalizationsDelegate extends LocalizationsDelegate { diff --git a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart index 788f77d670c..848aa952b2b 100644 --- a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart +++ b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_en.dart @@ -250,4 +250,15 @@ class VoicesLocalizationsEn extends VoicesLocalizations { @override String get drawerSpaceFundedProjects => 'Funded projects'; + + @override + String get fundedProjectSpace => 'Funded project space'; + + @override + String noOfFundedProposals(int count) { + return 'Funded proposals ($count)'; + } + + @override + String get followed => 'Followed'; } diff --git a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart index d2689af3d26..7049f13b836 100644 --- a/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart +++ b/catalyst_voices/packages/catalyst_voices_localization/lib/generated/catalyst_voices_localizations_es.dart @@ -250,4 +250,15 @@ class VoicesLocalizationsEs extends VoicesLocalizations { @override String get drawerSpaceFundedProjects => 'Funded projects'; + + @override + String get fundedProjectSpace => 'Funded project space'; + + @override + String noOfFundedProposals(int count) { + return 'Funded proposals ($count)'; + } + + @override + String get followed => 'Followed'; } diff --git a/catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb b/catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb index 7416217c202..a4fe26a9ade 100644 --- a/catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb +++ b/catalyst_voices/packages/catalyst_voices_localization/lib/l10n/intl_en.arb @@ -296,5 +296,22 @@ "drawerSpaceFundedProjects": "Funded projects", "@drawerSpaceFundedProjects": { "description": "Name shown in spaces shell drawer" + }, + "fundedProjectSpace": "Funded project space", + "@fundedProjectSpace": { + "description": "Title of the funded project space" + }, + "noOfFundedProposals": "Funded proposals ({count})", + "@noOfFundedProposals": { + "description": "Tab label for funded proposals in funded projects space", + "placeholders": { + "count": { + "type": "int" + } + } + }, + "followed": "Followed", + "@followed": { + "description": "Refers to a list of followed items." } } \ No newline at end of file