diff --git a/catalyst_voices/apps/voices/lib/pages/discovery/discovery_page.dart b/catalyst_voices/apps/voices/lib/pages/discovery/discovery_page.dart index 553506d16d7..0845ea99332 100644 --- a/catalyst_voices/apps/voices/lib/pages/discovery/discovery_page.dart +++ b/catalyst_voices/apps/voices/lib/pages/discovery/discovery_page.dart @@ -8,6 +8,7 @@ import 'package:catalyst_voices/pages/discovery/sections/stay_involved.dart'; import 'package:catalyst_voices/pages/discovery/state_selectors/campaign_categories_state_selector.dart'; import 'package:catalyst_voices/pages/discovery/state_selectors/current_campaign_selector.dart'; import 'package:catalyst_voices/pages/discovery/state_selectors/most_recent_proposals_selector.dart'; +import 'package:catalyst_voices/widgets/common/infrastructure/voices_wide_screen_constrained.dart'; import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart'; import 'package:flutter/material.dart'; @@ -36,7 +37,12 @@ class _Body extends StatelessWidget { const CampaignCategoriesStateSelector(), const StayInvolved(), const MostRecentProposalsSelector(), - ], + ].constrainedDelegate( + excludePredicate: (widget) => + widget is CampaignHeroSection || + widget is MostRecentProposalsSelector || + widget is HowItWorks, + ), ), ), ], diff --git a/catalyst_voices/apps/voices/lib/pages/discovery/sections/current_campaign.dart b/catalyst_voices/apps/voices/lib/pages/discovery/sections/current_campaign.dart index 5b81330228e..74dcfdd056c 100644 --- a/catalyst_voices/apps/voices/lib/pages/discovery/sections/current_campaign.dart +++ b/catalyst_voices/apps/voices/lib/pages/discovery/sections/current_campaign.dart @@ -23,6 +23,7 @@ class CurrentCampaign extends StatelessWidget { Widget build(BuildContext context) { return Column( mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.only(left: 120, top: 64, right: 120), diff --git a/catalyst_voices/apps/voices/lib/pages/discovery/sections/most_recent_proposals.dart b/catalyst_voices/apps/voices/lib/pages/discovery/sections/most_recent_proposals.dart index 283cdde2813..ca22d2d64aa 100644 --- a/catalyst_voices/apps/voices/lib/pages/discovery/sections/most_recent_proposals.dart +++ b/catalyst_voices/apps/voices/lib/pages/discovery/sections/most_recent_proposals.dart @@ -78,7 +78,10 @@ class _LatestProposalsState extends State { Widget build(BuildContext context) { return Container( key: const Key('MostRecentProposals'), - constraints: const BoxConstraints(maxHeight: 900), + constraints: const BoxConstraints.tightFor( + height: 800, + width: double.infinity, + ), decoration: BoxDecoration( image: DecorationImage( image: CatalystImage.asset( @@ -87,80 +90,83 @@ class _LatestProposalsState extends State { fit: BoxFit.cover, ), ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(height: 72), - Text( - key: const Key('MostRecentProposalsTitle'), - context.l10n.mostRecent, - style: context.textTheme.headlineLarge?.copyWith( - color: ThemeBuilder.buildTheme().colors.textOnPrimaryWhite, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 100), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(height: 72), + Text( + key: const Key('MostRecentProposalsTitle'), + context.l10n.mostRecent, + style: context.textTheme.headlineLarge?.copyWith( + color: ThemeBuilder.buildTheme().colors.textOnPrimaryWhite, + ), ), - ), - const SizedBox(height: 48), - MouseRegion( - cursor: SystemMouseCursors.click, - child: GestureDetector( - onHorizontalDragUpdate: _onHorizontalDrag, - child: SizedBox( - height: 440, - child: Center( - child: ListView.separated( - controller: _scrollController, - shrinkWrap: true, - physics: const ClampingScrollPhysics(), - padding: const EdgeInsets.symmetric(horizontal: 120), - scrollDirection: Axis.horizontal, - itemCount: widget.proposals.length, - itemBuilder: (context, index) { - final proposal = widget.proposals[index]; - final ref = proposal.ref; - return Skeletonizer( - enabled: widget.isLoading, - child: PendingProposalCard( - key: Key('PendingProposalCard_$ref'), - proposal: proposal, - onTap: () { - unawaited( - ProposalRoute( - proposalId: ref.id, - version: ref.version, - ).push(context), - ); - }, - onFavoriteChanged: (value) async { - final bloc = context.read(); - if (value) { - await bloc.addFavorite(ref); - } else { - await bloc.removeFavorite(ref); - } - }, - isFavorite: proposal.isFavorite, - ), - ); - }, - separatorBuilder: (context, index) => - const SizedBox(width: 24), + const SizedBox(height: 48), + MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( + onHorizontalDragUpdate: _onHorizontalDrag, + child: SizedBox( + height: 440, + width: 1200, + child: Center( + child: ListView.separated( + controller: _scrollController, + shrinkWrap: true, + physics: const ClampingScrollPhysics(), + scrollDirection: Axis.horizontal, + itemCount: widget.proposals.length, + itemBuilder: (context, index) { + final proposal = widget.proposals[index]; + final ref = proposal.ref; + return Skeletonizer( + enabled: widget.isLoading, + child: PendingProposalCard( + key: Key('PendingProposalCard_$ref'), + proposal: proposal, + onTap: () { + unawaited( + ProposalRoute( + proposalId: ref.id, + version: ref.version, + ).push(context), + ); + }, + onFavoriteChanged: (value) async { + final bloc = context.read(); + if (value) { + await bloc.addFavorite(ref); + } else { + await bloc.removeFavorite(ref); + } + }, + isFavorite: proposal.isFavorite, + ), + ); + }, + separatorBuilder: (context, index) => + const SizedBox(width: 24), + ), ), ), ), ), - ), - const SizedBox(height: 16), - ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 360), - child: VoicesSlider( - key: const Key('MostRecentProposalsSlider'), - value: _scrollPercentage, - onChanged: _onSliderChanged, + const SizedBox(height: 16), + ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 360), + child: VoicesSlider( + key: const Key('MostRecentProposalsSlider'), + value: _scrollPercentage, + onChanged: _onSliderChanged, + ), ), - ), - const SizedBox(height: 16), - const _ViewAllProposalsButton(), - const SizedBox(height: 72), - ], + const SizedBox(height: 16), + const _ViewAllProposalsButton(), + const SizedBox(height: 72), + ], + ), ), ); } diff --git a/catalyst_voices/apps/voices/lib/widgets/common/infrastructure/voices_wide_screen_constrained.dart b/catalyst_voices/apps/voices/lib/widgets/common/infrastructure/voices_wide_screen_constrained.dart new file mode 100644 index 00000000000..4a5f8a0b7f3 --- /dev/null +++ b/catalyst_voices/apps/voices/lib/widgets/common/infrastructure/voices_wide_screen_constrained.dart @@ -0,0 +1,66 @@ +import 'package:flutter/material.dart'; + +bool _defaultExcludePredicate(Widget child) => false; + +typedef ExcludeWidgetPredicate = bool Function(Widget child); + +class VoicesWideScreenConstrained extends StatelessWidget { + /// Width of the screen. Defaults to 1440. When child has padding + /// of horizontal 120 so actual content is 1200 + final double maxWidth; + final Color? backgroundColor; + final Widget child; + + const VoicesWideScreenConstrained({ + super.key, + this.maxWidth = 1440, + this.backgroundColor, + required this.child, + }); + + @override + Widget build(BuildContext context) { + Widget content = Center( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: maxWidth), + child: child, + ), + ); + + if (backgroundColor != null) { + content = ColoredBox( + color: backgroundColor!, + child: content, + ); + } + + return content; + } +} + +extension ConstrainedListExtension on List { + List constrainedDelegate({ + double maxWidth = 1440, + ExcludeWidgetPredicate excludePredicate = _defaultExcludePredicate, + }) { + return map((widget) { + if (excludePredicate(widget)) { + return widget; + } + + return VoicesWideScreenConstrained( + maxWidth: maxWidth, + child: widget, + ); + }).toList(); + } +} + +extension ConstrainedWidgetExtension on Widget { + Widget withBackground(Color color) { + return VoicesWideScreenConstrained( + backgroundColor: color, + child: this, + ); + } +} diff --git a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_timeline.dart b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_timeline.dart index 1d6feefc9f2..b24a068aa8a 100644 --- a/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_timeline.dart +++ b/catalyst_voices/packages/internal/catalyst_voices_models/lib/src/campaign/campaign_timeline.dart @@ -50,7 +50,7 @@ extension CampaignTimelineX on CampaignTimeline { '''Participants submit initial proposals for ideas to solve challenges. A set amount of ada is allocated to the new funding round.''', timeline: DateRange( from: DateTime.utc(2025, 4, 30, 13, 20), - to: DateTime.utc(2025, 5, 7, 17, 00), + to: DateTime.utc(2025, 5, 13, 17, 00), ), stage: CampaignTimelineStage.proposalSubmission, ), @@ -84,15 +84,5 @@ extension CampaignTimelineX on CampaignTimeline { ), stage: CampaignTimelineStage.votingResults, ), - CampaignTimeline( - title: 'Project Onboarding', - description: - '''Votes are tallied and the results revealed. Voters and community reviewers receive their rewards.''', - timeline: DateRange( - from: DateTime.utc(2025, 5, 15, 17, 00), - to: null, - ), - stage: CampaignTimelineStage.projectOnboarding, - ), ]; }