From 8d0cf4ec22d68fa46ad56c72c6af625a46bee58e Mon Sep 17 00:00:00 2001 From: Damian Molinski Date: Fri, 6 Sep 2024 13:18:46 +0200 Subject: [PATCH 1/8] feat: wip --- catalyst_voices/lib/app/view/app_content.dart | 2 + .../treasury}/campaign_builder_panel.dart | 0 .../treasury}/campaign_comments_panel.dart | 0 .../pages/treasury}/campaign_details.dart | 1 - .../lib/pages/treasury/treasury_page.dart | 75 +++++++++-- .../lib/widgets/menu/voices_node_menu.dart | 2 +- .../voices_treasury_drawer.dart | 116 ------------------ .../treasury_space/voices_treasury_space.dart | 99 --------------- .../uikit_example/lib/examples_list.dart | 6 - 9 files changed, 71 insertions(+), 230 deletions(-) rename catalyst_voices/{uikit_example/lib/examples/treasury_space => lib/pages/treasury}/campaign_builder_panel.dart (100%) rename catalyst_voices/{uikit_example/lib/examples/treasury_space => lib/pages/treasury}/campaign_comments_panel.dart (100%) rename catalyst_voices/{uikit_example/lib/examples/treasury_space => lib/pages/treasury}/campaign_details.dart (97%) delete mode 100644 catalyst_voices/uikit_example/lib/examples/treasury_space/voices_treasury_drawer.dart delete mode 100644 catalyst_voices/uikit_example/lib/examples/treasury_space/voices_treasury_space.dart diff --git a/catalyst_voices/lib/app/view/app_content.dart b/catalyst_voices/lib/app/view/app_content.dart index 154f5803d14..756a6198c1c 100644 --- a/catalyst_voices/lib/app/view/app_content.dart +++ b/catalyst_voices/lib/app/view/app_content.dart @@ -28,6 +28,8 @@ final class AppContent extends StatelessWidget { supportedLocales: VoicesLocalizations.supportedLocales, localeListResolutionCallback: basicLocaleListResolution, routerConfig: routerConfig, + // Light mode is "go to" for now. + themeMode: ThemeMode.light, theme: ThemeBuilder.buildTheme(BrandKey.catalyst), darkTheme: ThemeBuilder.buildDarkTheme(BrandKey.catalyst), ); diff --git a/catalyst_voices/uikit_example/lib/examples/treasury_space/campaign_builder_panel.dart b/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart similarity index 100% rename from catalyst_voices/uikit_example/lib/examples/treasury_space/campaign_builder_panel.dart rename to catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart diff --git a/catalyst_voices/uikit_example/lib/examples/treasury_space/campaign_comments_panel.dart b/catalyst_voices/lib/pages/treasury/campaign_comments_panel.dart similarity index 100% rename from catalyst_voices/uikit_example/lib/examples/treasury_space/campaign_comments_panel.dart rename to catalyst_voices/lib/pages/treasury/campaign_comments_panel.dart diff --git a/catalyst_voices/uikit_example/lib/examples/treasury_space/campaign_details.dart b/catalyst_voices/lib/pages/treasury/campaign_details.dart similarity index 97% rename from catalyst_voices/uikit_example/lib/examples/treasury_space/campaign_details.dart rename to catalyst_voices/lib/pages/treasury/campaign_details.dart index 80b5d6312dc..6295ddb3d14 100644 --- a/catalyst_voices/uikit_example/lib/examples/treasury_space/campaign_details.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_details.dart @@ -1,7 +1,6 @@ import 'package:catalyst_voices/widgets/widgets.dart'; import 'package:catalyst_voices_shared/catalyst_voices_shared.dart'; import 'package:flutter/material.dart'; -import 'package:uikit_example/examples/treasury_space/voices_treasury_space.dart'; class CampaignDetails extends StatelessWidget { final VoicesNodeMenuController campaignSetupController; diff --git a/catalyst_voices/lib/pages/treasury/treasury_page.dart b/catalyst_voices/lib/pages/treasury/treasury_page.dart index d8684e7a0fb..bc184d389ea 100644 --- a/catalyst_voices/lib/pages/treasury/treasury_page.dart +++ b/catalyst_voices/lib/pages/treasury/treasury_page.dart @@ -1,18 +1,79 @@ +import 'package:catalyst_voices/pages/treasury/campaign_builder_panel.dart'; +import 'package:catalyst_voices/pages/treasury/campaign_comments_panel.dart'; +import 'package:catalyst_voices/pages/treasury/campaign_details.dart'; +import 'package:catalyst_voices/widgets/widgets.dart'; import 'package:flutter/material.dart'; -class TreasuryPage extends StatelessWidget { +/*final class CampaignSetupStep extends VoicesNodeMenuItem { + final String desc; + + const CampaignSetupStep({ + required super.id, + required String name, + required this.desc, + }) : super(label: name); + + /// Just syntax sugar. Semantically it makes more sense to have `name`. + String get name => label; +} + +const _campaignSetupSteps = [ + CampaignSetupStep( + id: 0, + name: 'Campaign title', + desc: 'F14 / Promote Social Entrepreneurs and' + ' a longer title up-to 60 characters', + ), + CampaignSetupStep( + id: 1, + name: 'Other topic 1', + desc: 'Other topic 1', + ), + CampaignSetupStep( + id: 2, + name: 'Other topic 2', + desc: 'Other topic 2', + ), + CampaignSetupStep( + id: 3, + name: 'Other topic 3', + desc: 'Other topic 3', + ), +];*/ + +class TreasuryPage extends StatefulWidget { const TreasuryPage({ super.key, }); + @override + State createState() => _TreasuryPageState(); +} + +class _TreasuryPageState extends State { + final _setupCampaignController = VoicesNodeMenuController(); + + @override + void dispose() { + _setupCampaignController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return Container( - color: Colors.yellow, - alignment: Alignment.center, - child: Text( - 'Treasury', - style: Theme.of(context).textTheme.titleLarge, + return SpaceScaffold( + left: CampaignBuilderPanel( + setupCampaignController: _setupCampaignController, + setupCampaignItems: [ + // + ], + ), + right: CampaignCommentsPanel(), + child: CampaignDetails( + campaignSetupController: _setupCampaignController, + steps: [ + // + ], ), ); } diff --git a/catalyst_voices/lib/widgets/menu/voices_node_menu.dart b/catalyst_voices/lib/widgets/menu/voices_node_menu.dart index 562d6d02e93..e10c71ed559 100644 --- a/catalyst_voices/lib/widgets/menu/voices_node_menu.dart +++ b/catalyst_voices/lib/widgets/menu/voices_node_menu.dart @@ -5,7 +5,7 @@ import 'package:collection/collection.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; -base class VoicesNodeMenuItem extends Equatable { +final class VoicesNodeMenuItem extends Equatable { final int id; final String label; diff --git a/catalyst_voices/uikit_example/lib/examples/treasury_space/voices_treasury_drawer.dart b/catalyst_voices/uikit_example/lib/examples/treasury_space/voices_treasury_drawer.dart deleted file mode 100644 index d0fea242df7..00000000000 --- a/catalyst_voices/uikit_example/lib/examples/treasury_space/voices_treasury_drawer.dart +++ /dev/null @@ -1,116 +0,0 @@ -import 'package:catalyst_voices/widgets/widgets.dart'; -import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; -import 'package:catalyst_voices_brands/catalyst_voices_brands.dart'; -import 'package:catalyst_voices_models/catalyst_voices_models.dart'; -import 'package:flutter/material.dart'; - -class VoicesTreasuryDrawer extends StatelessWidget { - const VoicesTreasuryDrawer({ - super.key, - }); - - @override - Widget build(BuildContext context) { - return VoicesDrawer( - children: [ - _Treasury(), - ], - bottom: VoicesDrawerSpaceChooser( - currentSpace: Space.treasury, - onChanged: (value) {}, - ), - ); - } -} - -class _Treasury extends StatefulWidget { - const _Treasury(); - - @override - State<_Treasury> createState() => _TreasuryState(); -} - -class _TreasuryState extends State<_Treasury> { - bool _isExpanded = true; - - @override - Widget build(BuildContext context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - _TreasuryHeader( - onTap: () { - setState(() { - _isExpanded = !_isExpanded; - }); - }, - isExpanded: _isExpanded, - ), - if (_isExpanded) ...[ - SectionHeader( - leading: SizedBox(width: 12), - title: Text('Individual private campaigns'), - ), - VoicesDrawerNavItem( - name: 'Fund name 1', - status: ProposalStatus.ready, - ), - VoicesDrawerNavItem( - name: 'Campaign 1', - status: ProposalStatus.draft, - ), - VoicesDrawerNavItem( - name: 'What happens with a campaign title that is longer that', - status: ProposalStatus.draft, - ), - ], - ], - ); - } -} - -class _TreasuryHeader extends StatelessWidget { - final VoidCallback? onTap; - final bool isExpanded; - - const _TreasuryHeader({ - this.onTap, - this.isExpanded = false, - }); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - return GestureDetector( - onTap: onTap, - child: Container( - padding: - EdgeInsets.symmetric(vertical: 14).add(EdgeInsets.only(left: 16)), - child: Row( - children: [ - VoicesAvatar( - icon: Icon(CatalystVoicesIcons.cash), - foregroundColor: theme.colors.iconsSuccess, - backgroundColor: theme.colors.successContainer, - ), - SizedBox(width: 12), - Expanded( - child: Text( - 'Treasury', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: theme.textTheme.titleMedium - ?.copyWith(color: theme.colors.textPrimary), - ), - ), - ChevronExpandButton( - isExpanded: isExpanded, - onTap: onTap, - ), - ], - ), - ), - ); - } -} diff --git a/catalyst_voices/uikit_example/lib/examples/treasury_space/voices_treasury_space.dart b/catalyst_voices/uikit_example/lib/examples/treasury_space/voices_treasury_space.dart deleted file mode 100644 index 14e8a5d7af0..00000000000 --- a/catalyst_voices/uikit_example/lib/examples/treasury_space/voices_treasury_space.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:catalyst_voices/widgets/widgets.dart'; -import 'package:catalyst_voices_brands/catalyst_voices_brands.dart'; -import 'package:flutter/material.dart'; -import 'package:uikit_example/examples/treasury_space/campaign_builder_panel.dart'; -import 'package:uikit_example/examples/treasury_space/campaign_comments_panel.dart'; -import 'package:uikit_example/examples/treasury_space/campaign_details.dart'; -import 'package:uikit_example/examples/treasury_space/voices_treasury_drawer.dart'; - -final class CampaignSetupStep extends VoicesNodeMenuItem { - final String desc; - - const CampaignSetupStep({ - required super.id, - required String name, - required this.desc, - }) : super(label: name); - - /// Just syntax sugar. Semantically it makes more sense to have `name`. - String get name => label; -} - -const _campaignSetupSteps = [ - CampaignSetupStep( - id: 0, - name: 'Campaign title', - desc: 'F14 / Promote Social Entrepreneurs and' - ' a longer title up-to 60 characters', - ), - CampaignSetupStep( - id: 1, - name: 'Other topic 1', - desc: 'Other topic 1', - ), - CampaignSetupStep( - id: 2, - name: 'Other topic 2', - desc: 'Other topic 2', - ), - CampaignSetupStep( - id: 3, - name: 'Other topic 3', - desc: 'Other topic 3', - ), -]; - -class VoicesTreasurySpace extends StatefulWidget { - static const String route = '/treasury-space'; - - const VoicesTreasurySpace({ - super.key, - }); - - @override - State createState() => _VoicesTreasurySpaceState(); -} - -class _VoicesTreasurySpaceState extends State { - final _setupCampaignController = VoicesNodeMenuController( - VoicesNodeMenuData( - selectedItemId: _campaignSetupSteps.first.id, - isExpanded: true, - ), - ); - - @override - void dispose() { - _setupCampaignController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Theme( - data: ThemeBuilder.buildTheme(BrandKey.catalyst), - child: Builder( - builder: (context) { - return Scaffold( - appBar: VoicesAppBar( - backgroundColor: - Theme.of(context).colors.onSurfaceNeutralOpaqueLv0, - ), - drawer: VoicesTreasuryDrawer(), - body: SpaceScaffold( - left: CampaignBuilderPanel( - setupCampaignController: _setupCampaignController, - setupCampaignItems: _campaignSetupSteps, - ), - right: CampaignCommentsPanel(), - child: CampaignDetails( - campaignSetupController: _setupCampaignController, - steps: _campaignSetupSteps, - ), - ), - ); - }, - ), - ); - } -} diff --git a/catalyst_voices/uikit_example/lib/examples_list.dart b/catalyst_voices/uikit_example/lib/examples_list.dart index 90983ced1cf..53c273a7c54 100644 --- a/catalyst_voices/uikit_example/lib/examples_list.dart +++ b/catalyst_voices/uikit_example/lib/examples_list.dart @@ -4,7 +4,6 @@ import 'package:catalyst_voices/widgets/menu/voices_list_tile.dart'; import 'package:catalyst_voices/widgets/separators/voices_divider.dart'; import 'package:catalyst_voices/widgets/separators/voices_text_divider.dart'; import 'package:flutter/material.dart'; -import 'package:uikit_example/examples/treasury_space/voices_treasury_space.dart'; import 'package:uikit_example/examples/voices_avatar_example.dart'; import 'package:uikit_example/examples/voices_badge_example.dart'; import 'package:uikit_example/examples/voices_buttons_example.dart'; @@ -45,11 +44,6 @@ class ExamplesListPage extends StatelessWidget { route: VoicesSpacesExample.route, page: VoicesSpacesExample(), ), - ExampleTile( - title: 'VoicesTreasurySpace', - route: VoicesTreasurySpace.route, - page: VoicesTreasurySpace(), - ), ]; } From ab84a6f226f9c9b21ef9c9449873e0b7f55c31cc Mon Sep 17 00:00:00 2001 From: Damian Molinski Date: Mon, 9 Sep 2024 14:08:33 +0200 Subject: [PATCH 2/8] feat: introduce TreasuryCampaignBuilder and related widgets --- .../treasury/campaign_builder_panel.dart | 73 ++++++++---- .../lib/pages/treasury/campaign_details.dart | 109 ++++++++++++------ .../treasury_campaign_builder_ext.dart | 29 +++++ .../lib/pages/treasury/treasury_page.dart | 74 +++++------- .../lib/widgets/menu/voices_node_menu.dart | 81 ++++++++----- .../lib/src/catalyst_voices_models.dart | 3 + .../treasury/treasury_campaign_builder.dart | 15 +++ .../treasury/treasury_campaign_segment.dart | 25 ++++ .../treasury_campaign_segment_step.dart | 37 ++++++ .../lib/examples/voices_menu_example.dart | 6 - 10 files changed, 313 insertions(+), 139 deletions(-) create mode 100644 catalyst_voices/lib/pages/treasury/treasury_campaign_builder_ext.dart create mode 100644 catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_builder.dart create mode 100644 catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_segment.dart create mode 100644 catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_segment_step.dart diff --git a/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart b/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart index fbaf1c9aca6..cdc9e96e876 100644 --- a/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart @@ -1,49 +1,72 @@ +import 'package:catalyst_voices/pages/treasury/treasury_campaign_builder_ext.dart'; import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; class CampaignBuilderPanel extends StatelessWidget { - final VoicesNodeMenuController setupCampaignController; - final List setupCampaignItems; + final TreasuryCampaignBuilder builder; + final Map stepsControllers; const CampaignBuilderPanel({ - required this.setupCampaignController, - required this.setupCampaignItems, + required this.builder, + required this.stepsControllers, }); @override Widget build(BuildContext context) { return SpaceSidePanel( isLeft: true, + // TODO: loc name: 'Campaign builder', onCollapseTap: () {}, tabs: [ - SpaceSidePanelTab( - name: 'Segments', - body: Column( - children: [ - VoicesNodeMenu( - name: 'Setup Campaign', - controller: setupCampaignController, - items: setupCampaignItems, - onSelectionChanged: _updateSetupMenuSelection, - onExpandChanged: _updateSetupMenuExpand, - ), - ], + if (builder.segments.isNotEmpty) + SpaceSidePanelTab( + // TODO: loc + name: 'Segments', + body: Column( + children: builder.segments.map( + (segment) { + return _CampaignSegmentBody( + key: ValueKey('CampaignSegment${segment.id}Key'), + segment: segment, + controller: stepsControllers[segment.id], + ); + }, + ).toList(), + ), ), - ), ], ); } +} - void _updateSetupMenuSelection(int? value) { - if (value == null) { - return; - } +class _CampaignSegmentBody extends StatelessWidget { + final TreasuryCampaignSegment segment; + final VoicesNodeMenuController? controller; - setupCampaignController.selected = value; - } + const _CampaignSegmentBody({ + super.key, + required this.segment, + this.controller, + }); - void _updateSetupMenuExpand(bool value) { - setupCampaignController.isExpanded = value; + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + + return VoicesNodeMenu( + name: segment.localizedName(l10n), + controller: controller, + items: segment.steps.map( + (step) { + return VoicesNodeMenuItem( + id: step.id, + label: step.localizedName(l10n), + ); + }, + ).toList(), + ); } } diff --git a/catalyst_voices/lib/pages/treasury/campaign_details.dart b/catalyst_voices/lib/pages/treasury/campaign_details.dart index 6295ddb3d14..cb8fb4197d3 100644 --- a/catalyst_voices/lib/pages/treasury/campaign_details.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_details.dart @@ -1,40 +1,46 @@ +import 'package:catalyst_voices/pages/treasury/treasury_campaign_builder_ext.dart'; import 'package:catalyst_voices/widgets/widgets.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'; class CampaignDetails extends StatelessWidget { - final VoicesNodeMenuController campaignSetupController; - final List steps; + final TreasuryCampaignBuilder builder; + final Map stepsControllers; const CampaignDetails({ super.key, - required this.campaignSetupController, - required this.steps, + required this.builder, + required this.stepsControllers, }); @override Widget build(BuildContext context) { - return ListView( + return ListView.builder( padding: const EdgeInsets.only(top: 10), - children: [ - _ListenableCampaignSetupDetails( - key: ValueKey('CampaignSetupDetailsKey'), - controller: campaignSetupController, - steps: steps, - ), - ], + itemCount: builder.segments.length, + itemBuilder: (context, index) { + final segment = builder.segments[index]; + + return _ListenableSegmentDetails( + key: ValueKey('ListenableSegment${segment.id}DetailsKey'), + segment: segment, + controller: stepsControllers[segment.id]!, + ); + }, ); } } -class _ListenableCampaignSetupDetails extends StatelessWidget { +class _ListenableSegmentDetails extends StatelessWidget { + final TreasuryCampaignSegment segment; final VoicesNodeMenuController controller; - final List steps; - const _ListenableCampaignSetupDetails({ + const _ListenableSegmentDetails({ super.key, + required this.segment, required this.controller, - required this.steps, }); @override @@ -42,12 +48,14 @@ class _ListenableCampaignSetupDetails extends StatelessWidget { return ValueListenableBuilder( valueListenable: controller, builder: (context, value, child) { - return _CampaignSetupDetails( - campaignSetupSteps: steps, - selected: controller.value.selectedItemId, - isExpanded: controller.value.isExpanded, + return _SegmentDetails( + key: ValueKey('Segment${segment.id}DetailsKey'), + name: segment.localizedName(context.l10n), + steps: segment.steps, + selected: controller.selected, + isExpanded: controller.isExpanded, onChevronTap: () { - controller.isExpanded = !controller.value.isExpanded; + controller.isExpanded = !controller.isExpanded; }, ); }, @@ -55,14 +63,17 @@ class _ListenableCampaignSetupDetails extends StatelessWidget { } } -class _CampaignSetupDetails extends StatelessWidget { - final List campaignSetupSteps; +class _SegmentDetails extends StatelessWidget { + final String name; + final List steps; final int? selected; final bool isExpanded; final VoidCallback? onChevronTap; - const _CampaignSetupDetails({ - required this.campaignSetupSteps, + const _SegmentDetails({ + super.key, + required this.name, + required this.steps, this.selected, this.isExpanded = false, this.onChevronTap, @@ -77,20 +88,19 @@ class _CampaignSetupDetails extends StatelessWidget { onTap: onChevronTap, isExpanded: isExpanded, ), - name: 'Setup Campaign', + name: name, isHighlighted: isExpanded, ), if (isExpanded) - ...campaignSetupSteps.map( + ...steps.map( (step) { - return WorkspaceTileContainer( + return _StepDetails( key: ValueKey('WorkspaceStep${step.id}TileKey'), + id: step.id, + name: step.localizedName(context.l10n), + desc: step.tempDescription(), isSelected: step.id == selected, - name: step.name, - headerActions: [ - VoicesTextButton(child: Text('Edit')), - ], - content: Text(step.desc), + isEditable: step.isEditable, ); }, ) @@ -98,3 +108,36 @@ class _CampaignSetupDetails extends StatelessWidget { ); } } + +class _StepDetails extends StatelessWidget { + const _StepDetails({ + super.key, + required this.id, + required this.name, + required this.desc, + this.isSelected = false, + this.isEditable = false, + }); + + final int id; + final String name; + final String desc; + final bool isSelected; + final bool isEditable; + + @override + Widget build(BuildContext context) { + return WorkspaceTileContainer( + name: name, + isSelected: isSelected, + headerActions: [ + // TODO: loc + VoicesTextButton( + child: Text('Edit'), + onTap: isEditable ? () {} : null, + ), + ], + content: Text(desc), + ); + } +} diff --git a/catalyst_voices/lib/pages/treasury/treasury_campaign_builder_ext.dart b/catalyst_voices/lib/pages/treasury/treasury_campaign_builder_ext.dart new file mode 100644 index 00000000000..fa65a929a33 --- /dev/null +++ b/catalyst_voices/lib/pages/treasury/treasury_campaign_builder_ext.dart @@ -0,0 +1,29 @@ +import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; + +extension TreasuryCampaignSegmentExt on TreasuryCampaignSegment { + // TODO: loc + String localizedName(VoicesLocalizations localizations) { + return switch (this) { + TreasuryCampaignSetup() => 'Setup Campaign', + }; + } +} + +extension TreasuryCampaignSegmentStepExt on TreasuryCampaignSegmentStep { + // TODO: loc + String localizedName(VoicesLocalizations localizations) { + return switch (this) { + TreasuryCampaignTitle() => 'Campaign title', + TreasuryCampaignTopicX(:final nr) => 'Other topic $nr', + }; + } + + String tempDescription() { + return switch (this) { + TreasuryCampaignTitle() => + 'F14 / Promote Social Entrepreneurs and a longer title up-to 60 characters', + TreasuryCampaignTopicX(:final nr) => 'Other topic $nr', + }; + } +} diff --git a/catalyst_voices/lib/pages/treasury/treasury_page.dart b/catalyst_voices/lib/pages/treasury/treasury_page.dart index bc184d389ea..42fc7efb911 100644 --- a/catalyst_voices/lib/pages/treasury/treasury_page.dart +++ b/catalyst_voices/lib/pages/treasury/treasury_page.dart @@ -2,44 +2,24 @@ import 'package:catalyst_voices/pages/treasury/campaign_builder_panel.dart'; import 'package:catalyst_voices/pages/treasury/campaign_comments_panel.dart'; import 'package:catalyst_voices/pages/treasury/campaign_details.dart'; import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; -/*final class CampaignSetupStep extends VoicesNodeMenuItem { - final String desc; - - const CampaignSetupStep({ - required super.id, - required String name, - required this.desc, - }) : super(label: name); - - /// Just syntax sugar. Semantically it makes more sense to have `name`. - String get name => label; -} - -const _campaignSetupSteps = [ - CampaignSetupStep( - id: 0, - name: 'Campaign title', - desc: 'F14 / Promote Social Entrepreneurs and' - ' a longer title up-to 60 characters', - ), - CampaignSetupStep( - id: 1, - name: 'Other topic 1', - desc: 'Other topic 1', - ), - CampaignSetupStep( - id: 2, - name: 'Other topic 2', - desc: 'Other topic 2', - ), - CampaignSetupStep( - id: 3, - name: 'Other topic 3', - desc: 'Other topic 3', - ), -];*/ +const _setupSegmentId = 'setup'; + +final _campaignBuilder = TreasuryCampaignBuilder( + segments: [ + TreasuryCampaignSetup( + id: _setupSegmentId, + steps: [ + TreasuryCampaignTitle(id: 0, isEditable: true), + TreasuryCampaignTopicX(id: 1, nr: 1), + TreasuryCampaignTopicX(id: 2, nr: 2), + TreasuryCampaignTopicX(id: 3, nr: 2), + ], + ), + ], +); class TreasuryPage extends StatefulWidget { const TreasuryPage({ @@ -51,11 +31,17 @@ class TreasuryPage extends StatefulWidget { } class _TreasuryPageState extends State { - final _setupCampaignController = VoicesNodeMenuController(); + // TODO(damian-molinski): Build VoicesNodeMenuControllerScope widget + final _controllers = { + _setupSegmentId: VoicesNodeMenuController(), + }; @override void dispose() { - _setupCampaignController.dispose(); + for (final controller in _controllers.values) { + controller.dispose(); + } + _controllers.clear(); super.dispose(); } @@ -63,17 +49,13 @@ class _TreasuryPageState extends State { Widget build(BuildContext context) { return SpaceScaffold( left: CampaignBuilderPanel( - setupCampaignController: _setupCampaignController, - setupCampaignItems: [ - // - ], + builder: _campaignBuilder, + stepsControllers: _controllers, ), right: CampaignCommentsPanel(), child: CampaignDetails( - campaignSetupController: _setupCampaignController, - steps: [ - // - ], + builder: _campaignBuilder, + stepsControllers: _controllers, ), ); } diff --git a/catalyst_voices/lib/widgets/menu/voices_node_menu.dart b/catalyst_voices/lib/widgets/menu/voices_node_menu.dart index e10c71ed559..6db08c282e3 100644 --- a/catalyst_voices/lib/widgets/menu/voices_node_menu.dart +++ b/catalyst_voices/lib/widgets/menu/voices_node_menu.dart @@ -8,37 +8,43 @@ import 'package:flutter/material.dart'; final class VoicesNodeMenuItem extends Equatable { final int id; final String label; + final bool isEnabled; const VoicesNodeMenuItem({ required this.id, required this.label, + this.isEnabled = true, }); @override - List get props => [id, label]; + List get props => [ + id, + label, + isEnabled, + ]; } -final class VoicesNodeMenuData extends Equatable { +final class VoicesNodeMenuStateData extends Equatable { final int? selectedItemId; final bool isExpanded; - const VoicesNodeMenuData({ + const VoicesNodeMenuStateData({ this.selectedItemId, this.isExpanded = false, }); - VoicesNodeMenuData copyWith({ + VoicesNodeMenuStateData copyWith({ int? selectedItemId, bool? isExpanded, }) { - return VoicesNodeMenuData( + return VoicesNodeMenuStateData( selectedItemId: selectedItemId ?? this.selectedItemId, isExpanded: isExpanded ?? this.isExpanded, ); } - VoicesNodeMenuData clearSelection() { - return VoicesNodeMenuData( + VoicesNodeMenuStateData clearSelection() { + return VoicesNodeMenuStateData( selectedItemId: null, isExpanded: isExpanded, ); @@ -51,64 +57,80 @@ final class VoicesNodeMenuData extends Equatable { ]; } -final class VoicesNodeMenuController extends ValueNotifier { +final class VoicesNodeMenuController + extends ValueNotifier { VoicesNodeMenuController([ - super._value = const VoicesNodeMenuData(), + super._value = const VoicesNodeMenuStateData(), ]); + int? get selected => value.selectedItemId; + set selected(int? newValue) { value = newValue != null ? value.copyWith(selectedItemId: newValue) : value.clearSelection(); } + bool get isExpanded => value.isExpanded; + set isExpanded(bool newValue) { value = value.copyWith(isExpanded: newValue); } } -class VoicesNodeMenu extends StatelessWidget { +class VoicesNodeMenu extends StatefulWidget { final String name; - final VoicesNodeMenuController controller; + final VoicesNodeMenuController? controller; final List items; - final ValueChanged? onSelectionChanged; - final ValueChanged? onExpandChanged; - - bool get _canTapItem => onSelectionChanged != null; - - bool get _canToggleExpand => onExpandChanged != null; + final bool isExpandable; const VoicesNodeMenu({ super.key, required this.name, - required this.controller, + this.controller, required this.items, - this.onSelectionChanged, - this.onExpandChanged, + this.isExpandable = true, }); + @override + State createState() => _VoicesNodeMenuState(); +} + +class _VoicesNodeMenuState extends State { + VoicesNodeMenuController? _controller; + + VoicesNodeMenuController get _effectiveController => + widget.controller ?? (_controller ??= VoicesNodeMenuController()); + + @override + void dispose() { + _controller?.dispose(); + _controller = null; + super.dispose(); + } + @override Widget build(BuildContext context) { return ValueListenableBuilder( - valueListenable: controller, + valueListenable: _effectiveController, builder: (context, value, child) { return SimpleTreeView( isExpanded: value.isExpanded, root: SimpleTreeViewRootRow( - onTap: _canToggleExpand ? _onRootTap : null, + onTap: widget.isExpandable ? _onRootTap : null, leading: [ _NodeIcon(isOpen: value.isExpanded), VoicesAssets.images.viewGrid.buildIcon(), ], - child: Text(name), + child: Text(widget.name), ), - children: items.mapIndexed( + children: widget.items.mapIndexed( (index, item) { return SimpleTreeViewChildRow( key: ValueKey('NodeMenu${item.id}RowKey'), - hasNext: index < items.length - 1, + hasNext: index < widget.items.length - 1, isSelected: item.id == value.selectedItemId, - onTap: _canTapItem ? () => _onMenuItemTap(item) : null, + onTap: item.isEnabled ? () => _onMenuItemTap(item) : null, child: Text(item.label), ); }, @@ -119,12 +141,13 @@ class VoicesNodeMenu extends StatelessWidget { } void _onRootTap() { - onExpandChanged?.call(!controller.value.isExpanded); + _effectiveController.isExpanded = !_effectiveController.isExpanded; } void _onMenuItemTap(VoicesNodeMenuItem item) { - final id = item.id != controller.value.selectedItemId ? item.id : null; - onSelectionChanged?.call(id); + final id = item.id != _effectiveController.selected ? item.id : null; + + _effectiveController.selected = id; } } diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/catalyst_voices_models.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/catalyst_voices_models.dart index 9c8052769c7..3cd21da9416 100644 --- a/catalyst_voices/packages/catalyst_voices_models/lib/src/catalyst_voices_models.dart +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/catalyst_voices_models.dart @@ -7,4 +7,7 @@ export 'proposal/pending_proposal.dart'; export 'proposal/proposal_status.dart'; export 'session_data.dart'; export 'space.dart'; +export 'treasury/treasury_campaign_builder.dart'; +export 'treasury/treasury_campaign_segment.dart'; +export 'treasury/treasury_campaign_segment_step.dart'; export 'user/user.dart'; diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_builder.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_builder.dart new file mode 100644 index 00000000000..76763d6acbf --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_builder.dart @@ -0,0 +1,15 @@ +import 'package:catalyst_voices_models/src/treasury/treasury_campaign_segment.dart'; +import 'package:equatable/equatable.dart'; + +final class TreasuryCampaignBuilder extends Equatable { + TreasuryCampaignBuilder({ + required this.segments, + }); + + final List segments; + + @override + List get props => [ + segments, + ]; +} diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_segment.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_segment.dart new file mode 100644 index 00000000000..4afc1da2608 --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_segment.dart @@ -0,0 +1,25 @@ +import 'package:catalyst_voices_models/src/treasury/treasury_campaign_segment_step.dart'; +import 'package:equatable/equatable.dart'; + +sealed class TreasuryCampaignSegment extends Equatable { + final Object id; + final List steps; + + const TreasuryCampaignSegment({ + required this.id, + required this.steps, + }); + + @override + List get props => [ + id, + steps, + ]; +} + +final class TreasuryCampaignSetup extends TreasuryCampaignSegment { + const TreasuryCampaignSetup({ + required super.id, + required super.steps, + }); +} diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_segment_step.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_segment_step.dart new file mode 100644 index 00000000000..7df7fdc1efd --- /dev/null +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_segment_step.dart @@ -0,0 +1,37 @@ +import 'package:equatable/equatable.dart'; + +sealed class TreasuryCampaignSegmentStep extends Equatable { + final int id; + final bool isEditable; + + TreasuryCampaignSegmentStep({ + required this.id, + this.isEditable = false, + }); + + @override + List get props => [ + id, + isEditable, + ]; +} + +final class TreasuryCampaignTitle extends TreasuryCampaignSegmentStep { + TreasuryCampaignTitle({ + required super.id, + super.isEditable, + }); +} + +// Note. Temporary class representing dummy topic +final class TreasuryCampaignTopicX extends TreasuryCampaignSegmentStep { + final int nr; + + TreasuryCampaignTopicX({ + required super.id, + required this.nr, + }); + + @override + List get props => super.props + [nr]; +} diff --git a/catalyst_voices/uikit_example/lib/examples/voices_menu_example.dart b/catalyst_voices/uikit_example/lib/examples/voices_menu_example.dart index 39724dccdda..a46ac5b16f4 100644 --- a/catalyst_voices/uikit_example/lib/examples/voices_menu_example.dart +++ b/catalyst_voices/uikit_example/lib/examples/voices_menu_example.dart @@ -41,12 +41,6 @@ class _VoicesMenuExampleState extends State { VoicesNodeMenuItem(id: 1, label: 'Vote'), VoicesNodeMenuItem(id: 2, label: 'Results'), ], - onSelectionChanged: (value) { - _problemSensingController.selected = value; - }, - onExpandChanged: (value) { - _problemSensingController.isExpanded = value; - }, ), ].separatedBy(const SizedBox(height: 12)).toList(), ), From 5840801cdb94c2b9c18d3f66e973777bdc9f076e Mon Sep 17 00:00:00 2001 From: Damian Molinski Date: Mon, 9 Sep 2024 14:16:11 +0200 Subject: [PATCH 3/8] feat: initially expand setup segment --- catalyst_voices/lib/pages/treasury/treasury_page.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/catalyst_voices/lib/pages/treasury/treasury_page.dart b/catalyst_voices/lib/pages/treasury/treasury_page.dart index 42fc7efb911..5168b85fe76 100644 --- a/catalyst_voices/lib/pages/treasury/treasury_page.dart +++ b/catalyst_voices/lib/pages/treasury/treasury_page.dart @@ -33,7 +33,12 @@ class TreasuryPage extends StatefulWidget { class _TreasuryPageState extends State { // TODO(damian-molinski): Build VoicesNodeMenuControllerScope widget final _controllers = { - _setupSegmentId: VoicesNodeMenuController(), + _setupSegmentId: VoicesNodeMenuController( + VoicesNodeMenuStateData( + selectedItemId: 0, + isExpanded: true, + ), + ), }; @override From 83b94261e74b8758f17e88d68f6d5772289a9e68 Mon Sep 17 00:00:00 2001 From: Damian Molinski Date: Mon, 9 Sep 2024 14:31:50 +0200 Subject: [PATCH 4/8] feat: localization --- .../treasury/campaign_builder_panel.dart | 6 ++-- .../lib/pages/treasury/campaign_details.dart | 3 +- .../treasury_campaign_builder_ext.dart | 10 +++---- .../catalyst_voices_localizations.dart | 30 +++++++++++++++++++ .../catalyst_voices_localizations_en.dart | 15 ++++++++++ .../catalyst_voices_localizations_es.dart | 15 ++++++++++ .../lib/l10n/intl_en.arb | 20 +++++++++++++ 7 files changed, 87 insertions(+), 12 deletions(-) diff --git a/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart b/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart index cdc9e96e876..29bc7b76d6e 100644 --- a/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart @@ -17,14 +17,12 @@ class CampaignBuilderPanel extends StatelessWidget { Widget build(BuildContext context) { return SpaceSidePanel( isLeft: true, - // TODO: loc - name: 'Campaign builder', + name: context.l10n.treasuryCampaignBuilder, onCollapseTap: () {}, tabs: [ if (builder.segments.isNotEmpty) SpaceSidePanelTab( - // TODO: loc - name: 'Segments', + name: context.l10n.treasuryCampaignBuilderSegments, body: Column( children: builder.segments.map( (segment) { diff --git a/catalyst_voices/lib/pages/treasury/campaign_details.dart b/catalyst_voices/lib/pages/treasury/campaign_details.dart index cb8fb4197d3..e60ea6bb3df 100644 --- a/catalyst_voices/lib/pages/treasury/campaign_details.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_details.dart @@ -131,9 +131,8 @@ class _StepDetails extends StatelessWidget { name: name, isSelected: isSelected, headerActions: [ - // TODO: loc VoicesTextButton( - child: Text('Edit'), + child: Text(context.l10n.treasuryStepEdit), onTap: isEditable ? () {} : null, ), ], diff --git a/catalyst_voices/lib/pages/treasury/treasury_campaign_builder_ext.dart b/catalyst_voices/lib/pages/treasury/treasury_campaign_builder_ext.dart index fa65a929a33..b97e351243b 100644 --- a/catalyst_voices/lib/pages/treasury/treasury_campaign_builder_ext.dart +++ b/catalyst_voices/lib/pages/treasury/treasury_campaign_builder_ext.dart @@ -2,27 +2,25 @@ import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; extension TreasuryCampaignSegmentExt on TreasuryCampaignSegment { - // TODO: loc String localizedName(VoicesLocalizations localizations) { return switch (this) { - TreasuryCampaignSetup() => 'Setup Campaign', + TreasuryCampaignSetup() => localizations.treasuryCampaignSetup, }; } } extension TreasuryCampaignSegmentStepExt on TreasuryCampaignSegmentStep { - // TODO: loc String localizedName(VoicesLocalizations localizations) { return switch (this) { - TreasuryCampaignTitle() => 'Campaign title', + TreasuryCampaignTitle() => localizations.treasuryCampaignTitle, TreasuryCampaignTopicX(:final nr) => 'Other topic $nr', }; } String tempDescription() { return switch (this) { - TreasuryCampaignTitle() => - 'F14 / Promote Social Entrepreneurs and a longer title up-to 60 characters', + TreasuryCampaignTitle() => 'F14 / Promote Social Entrepreneurs and a ' + 'longer title up-to 60 characters', TreasuryCampaignTopicX(:final nr) => 'Other topic $nr', }; } 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 ea16018c9b0..adaabe76f1d 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 @@ -417,6 +417,36 @@ abstract class VoicesLocalizations { /// In en, this message translates to: /// **'Favorites'** String get favorites; + + /// Left panel name in treasury space + /// + /// In en, this message translates to: + /// **'Campaign builder'** + String get treasuryCampaignBuilder; + + /// Tab name in campaign builder panel + /// + /// In en, this message translates to: + /// **'Segments'** + String get treasuryCampaignBuilderSegments; + + /// Segment name + /// + /// In en, this message translates to: + /// **'Setup Campaign'** + String get treasuryCampaignSetup; + + /// Campaign title + /// + /// In en, this message translates to: + /// **'Campaign title'** + String get treasuryCampaignTitle; + + /// Button name in treasury step + /// + /// In en, this message translates to: + /// **'Edit'** + String get treasuryStepEdit; } 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 7216e6e5c07..2ccde898c07 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 @@ -220,4 +220,19 @@ class VoicesLocalizationsEn extends VoicesLocalizations { @override String get favorites => 'Favorites'; + + @override + String get treasuryCampaignBuilder => 'Campaign builder'; + + @override + String get treasuryCampaignBuilderSegments => 'Segments'; + + @override + String get treasuryCampaignSetup => 'Setup Campaign'; + + @override + String get treasuryCampaignTitle => 'Campaign title'; + + @override + String get treasuryStepEdit => 'Edit'; } 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 37dd2f52710..869ac1fcde8 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 @@ -220,4 +220,19 @@ class VoicesLocalizationsEs extends VoicesLocalizations { @override String get favorites => 'Favorites'; + + @override + String get treasuryCampaignBuilder => 'Campaign builder'; + + @override + String get treasuryCampaignBuilderSegments => 'Segments'; + + @override + String get treasuryCampaignSetup => 'Setup Campaign'; + + @override + String get treasuryCampaignTitle => 'Campaign title'; + + @override + String get treasuryStepEdit => 'Edit'; } 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 3a361c79c90..18b2898f87f 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 @@ -256,5 +256,25 @@ "favorites": "Favorites", "@favorites": { "description": "Refers to a list of favorites." + }, + "treasuryCampaignBuilder": "Campaign builder", + "@treasuryCampaignBuilder": { + "description": "Left panel name in treasury space" + }, + "treasuryCampaignBuilderSegments": "Segments", + "@treasuryCampaignBuilderSegments": { + "description": "Tab name in campaign builder panel" + }, + "treasuryCampaignSetup": "Setup Campaign", + "@treasuryCampaignSetup": { + "description": "Segment name" + }, + "treasuryCampaignTitle": "Campaign title", + "@treasuryCampaignTitle": { + "description": "Campaign title" + }, + "treasuryStepEdit": "Edit", + "@treasuryStepEdit": { + "description": "Button name in treasury step" } } \ No newline at end of file From a5715ddc51662c77a097c0e73cd298768fbb7bed Mon Sep 17 00:00:00 2001 From: Damian Molinski Date: Mon, 9 Sep 2024 14:35:06 +0200 Subject: [PATCH 5/8] refactor: Make ValueListenableBuilder unused child param underscored --- catalyst_voices/lib/pages/treasury/campaign_details.dart | 2 +- catalyst_voices/lib/widgets/menu/voices_node_menu.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/catalyst_voices/lib/pages/treasury/campaign_details.dart b/catalyst_voices/lib/pages/treasury/campaign_details.dart index e60ea6bb3df..f4b4c1448e6 100644 --- a/catalyst_voices/lib/pages/treasury/campaign_details.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_details.dart @@ -47,7 +47,7 @@ class _ListenableSegmentDetails extends StatelessWidget { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: controller, - builder: (context, value, child) { + builder: (context, value, _) { return _SegmentDetails( key: ValueKey('Segment${segment.id}DetailsKey'), name: segment.localizedName(context.l10n), diff --git a/catalyst_voices/lib/widgets/menu/voices_node_menu.dart b/catalyst_voices/lib/widgets/menu/voices_node_menu.dart index 6db08c282e3..b63b0adb59b 100644 --- a/catalyst_voices/lib/widgets/menu/voices_node_menu.dart +++ b/catalyst_voices/lib/widgets/menu/voices_node_menu.dart @@ -113,7 +113,7 @@ class _VoicesNodeMenuState extends State { Widget build(BuildContext context) { return ValueListenableBuilder( valueListenable: _effectiveController, - builder: (context, value, child) { + builder: (context, value, _) { return SimpleTreeView( isExpanded: value.isExpanded, root: SimpleTreeViewRootRow( From f73c448108dcf561d6c9b21ec029a09fc9a0432f Mon Sep 17 00:00:00 2001 From: Damian Molinski Date: Mon, 9 Sep 2024 16:29:32 +0200 Subject: [PATCH 6/8] feat: CampaignControllerScope --- .../treasury/campaign_builder_panel.dart | 8 +- .../lib/pages/treasury/campaign_details.dart | 8 +- .../treasury/campaign_segment_controller.dart | 117 ++++++++++++++++++ .../lib/pages/treasury/treasury_page.dart | 51 ++++---- .../lib/widgets/menu/voices_node_menu.dart | 5 +- 5 files changed, 152 insertions(+), 37 deletions(-) create mode 100644 catalyst_voices/lib/pages/treasury/campaign_segment_controller.dart diff --git a/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart b/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart index 29bc7b76d6e..99da07521ce 100644 --- a/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_builder_panel.dart @@ -1,3 +1,4 @@ +import 'package:catalyst_voices/pages/treasury/campaign_segment_controller.dart'; import 'package:catalyst_voices/pages/treasury/treasury_campaign_builder_ext.dart'; import 'package:catalyst_voices/widgets/widgets.dart'; import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; @@ -6,11 +7,9 @@ import 'package:flutter/material.dart'; class CampaignBuilderPanel extends StatelessWidget { final TreasuryCampaignBuilder builder; - final Map stepsControllers; const CampaignBuilderPanel({ required this.builder, - required this.stepsControllers, }); @override @@ -29,7 +28,10 @@ class CampaignBuilderPanel extends StatelessWidget { return _CampaignSegmentBody( key: ValueKey('CampaignSegment${segment.id}Key'), segment: segment, - controller: stepsControllers[segment.id], + controller: CampaignControllerScope.of( + context, + id: segment.id, + ), ); }, ).toList(), diff --git a/catalyst_voices/lib/pages/treasury/campaign_details.dart b/catalyst_voices/lib/pages/treasury/campaign_details.dart index f4b4c1448e6..001a07c2461 100644 --- a/catalyst_voices/lib/pages/treasury/campaign_details.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_details.dart @@ -1,3 +1,4 @@ +import 'package:catalyst_voices/pages/treasury/campaign_segment_controller.dart'; import 'package:catalyst_voices/pages/treasury/treasury_campaign_builder_ext.dart'; import 'package:catalyst_voices/widgets/widgets.dart'; import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; @@ -7,12 +8,10 @@ import 'package:flutter/material.dart'; class CampaignDetails extends StatelessWidget { final TreasuryCampaignBuilder builder; - final Map stepsControllers; const CampaignDetails({ super.key, required this.builder, - required this.stepsControllers, }); @override @@ -26,7 +25,10 @@ class CampaignDetails extends StatelessWidget { return _ListenableSegmentDetails( key: ValueKey('ListenableSegment${segment.id}DetailsKey'), segment: segment, - controller: stepsControllers[segment.id]!, + controller: CampaignControllerScope.of( + context, + id: segment.id, + ), ); }, ); diff --git a/catalyst_voices/lib/pages/treasury/campaign_segment_controller.dart b/catalyst_voices/lib/pages/treasury/campaign_segment_controller.dart new file mode 100644 index 00000000000..4cff5ba27db --- /dev/null +++ b/catalyst_voices/lib/pages/treasury/campaign_segment_controller.dart @@ -0,0 +1,117 @@ +import 'package:catalyst_voices/widgets/menu/voices_node_menu.dart'; +import 'package:flutter/material.dart'; + +typedef ControllerBuilder = CampaignController Function( + Object segmentId, +); + +final class CampaignControllerStateData extends VoicesNodeMenuStateData { + const CampaignControllerStateData({ + super.selectedItemId, + super.isExpanded, + }); +} + +/// Direct extension of [VoicesNodeMenuController]. +/// Probably we'll need extend controller with additional fields. +final class CampaignController extends VoicesNodeMenuController { + CampaignController(CampaignControllerStateData super._value); +} + +/// Keeps together [CampaignControllerStateData] tied to ids. +class CampaignControllerScope extends StatefulWidget { + final ControllerBuilder builder; + final Widget child; + + const CampaignControllerScope({ + super.key, + required this.builder, + required this.child, + }); + + /// The closes instance of [CampaignControllerScope] + /// that encloses the given context, or null if none found. + /// + /// Uses [builder] with given [id] to build [CampaignController] + /// if none already created for this [id]. + static CampaignController? maybeOf( + BuildContext context, { + required Object id, + }) { + return context + .findAncestorStateOfType<_CampaignControllerScopeState>() + ?._getSegmentController(id); + } + + /// Wrapper on [maybeOf] but forcing null unwrapping. + static CampaignController of( + BuildContext context, { + required Object id, + }) { + final controller = maybeOf(context, id: id); + + assert( + controller != null, + 'Unable to find CampaignControllerScope as parent widget', + ); + + return controller!; + } + + @override + State createState() { + return _CampaignControllerScopeState(); + } +} + +class _CampaignControllerScopeState extends State { + final _cache = {}; + + bool _debugDisposed = false; + + static bool _debugAssertNotDisposed( + _CampaignControllerScopeState screenState, + ) { + assert(() { + if (screenState._debugDisposed) { + throw FlutterError( + 'A ${screenState.runtimeType} was used after being disposed.\n' + 'Once you have called dispose() on a ${screenState.runtimeType}, it ' + 'can no longer be used.', + ); + } + return true; + }()); + return true; + } + + @override + void dispose() { + assert(_debugAssertNotDisposed(this)); + assert(() { + _debugDisposed = true; + return true; + }()); + + final controllers = List.of(_cache.values); + for (final controller in controllers) { + controller.dispose(); + } + _cache.clear(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } + + CampaignController _getSegmentController(Object segmentId) { + _debugAssertNotDisposed(this); + + return _cache.putIfAbsent( + segmentId, + () => widget.builder(segmentId), + ); + } +} diff --git a/catalyst_voices/lib/pages/treasury/treasury_page.dart b/catalyst_voices/lib/pages/treasury/treasury_page.dart index 5168b85fe76..f810ecc54d1 100644 --- a/catalyst_voices/lib/pages/treasury/treasury_page.dart +++ b/catalyst_voices/lib/pages/treasury/treasury_page.dart @@ -1,6 +1,7 @@ import 'package:catalyst_voices/pages/treasury/campaign_builder_panel.dart'; import 'package:catalyst_voices/pages/treasury/campaign_comments_panel.dart'; import 'package:catalyst_voices/pages/treasury/campaign_details.dart'; +import 'package:catalyst_voices/pages/treasury/campaign_segment_controller.dart'; import 'package:catalyst_voices/widgets/widgets.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; @@ -31,37 +32,31 @@ class TreasuryPage extends StatefulWidget { } class _TreasuryPageState extends State { - // TODO(damian-molinski): Build VoicesNodeMenuControllerScope widget - final _controllers = { - _setupSegmentId: VoicesNodeMenuController( - VoicesNodeMenuStateData( - selectedItemId: 0, - isExpanded: true, - ), - ), - }; - - @override - void dispose() { - for (final controller in _controllers.values) { - controller.dispose(); - } - _controllers.clear(); - super.dispose(); - } - @override Widget build(BuildContext context) { - return SpaceScaffold( - left: CampaignBuilderPanel( - builder: _campaignBuilder, - stepsControllers: _controllers, - ), - right: CampaignCommentsPanel(), - child: CampaignDetails( - builder: _campaignBuilder, - stepsControllers: _controllers, + return CampaignControllerScope( + builder: _buildSegmentController, + child: SpaceScaffold( + left: CampaignBuilderPanel( + builder: _campaignBuilder, + ), + right: CampaignCommentsPanel(), + child: CampaignDetails( + builder: _campaignBuilder, + ), ), ); } + + // Only creates initial controller one time + CampaignController _buildSegmentController(Object segmentId) { + final value = segmentId == _setupSegmentId + ? CampaignControllerStateData( + selectedItemId: 0, + isExpanded: true, + ) + : CampaignControllerStateData(); + + return CampaignController(value); + } } diff --git a/catalyst_voices/lib/widgets/menu/voices_node_menu.dart b/catalyst_voices/lib/widgets/menu/voices_node_menu.dart index b63b0adb59b..e1dac75509c 100644 --- a/catalyst_voices/lib/widgets/menu/voices_node_menu.dart +++ b/catalyst_voices/lib/widgets/menu/voices_node_menu.dart @@ -24,7 +24,7 @@ final class VoicesNodeMenuItem extends Equatable { ]; } -final class VoicesNodeMenuStateData extends Equatable { +class VoicesNodeMenuStateData extends Equatable { final int? selectedItemId; final bool isExpanded; @@ -57,8 +57,7 @@ final class VoicesNodeMenuStateData extends Equatable { ]; } -final class VoicesNodeMenuController - extends ValueNotifier { +class VoicesNodeMenuController extends ValueNotifier { VoicesNodeMenuController([ super._value = const VoicesNodeMenuStateData(), ]); From ab1007d1b33de7a951ba5bd5d9e2c169481c8d3a Mon Sep 17 00:00:00 2001 From: Damian Molinski Date: Tue, 10 Sep 2024 09:34:58 +0200 Subject: [PATCH 7/8] feat: Treasury drawer --- .../spaces/individual_private_campaigns.dart | 32 ++++++ .../lib/pages/spaces/spaces_drawer.dart | 102 ++++++++++++++++++ .../lib/pages/spaces/spaces_shell_page.dart | 44 +------- .../lib/widgets/avatars/space_avatar.dart | 86 +++++++++++++++ .../drawer/voices_drawer_space_chooser.dart | 57 +--------- catalyst_voices/lib/widgets/widgets.dart | 1 + .../catalyst_voices_localizations.dart | 30 ++++++ .../catalyst_voices_localizations_en.dart | 15 +++ .../catalyst_voices_localizations_es.dart | 15 +++ .../lib/l10n/intl_en.arb | 20 ++++ .../treasury/treasury_campaign_builder.dart | 4 +- 11 files changed, 309 insertions(+), 97 deletions(-) create mode 100644 catalyst_voices/lib/pages/spaces/individual_private_campaigns.dart create mode 100644 catalyst_voices/lib/pages/spaces/spaces_drawer.dart create mode 100644 catalyst_voices/lib/widgets/avatars/space_avatar.dart diff --git a/catalyst_voices/lib/pages/spaces/individual_private_campaigns.dart b/catalyst_voices/lib/pages/spaces/individual_private_campaigns.dart new file mode 100644 index 00000000000..db2374d5d61 --- /dev/null +++ b/catalyst_voices/lib/pages/spaces/individual_private_campaigns.dart @@ -0,0 +1,32 @@ +import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:flutter/material.dart'; + +class IndividualPrivateCampaigns extends StatelessWidget { + const IndividualPrivateCampaigns({super.key}); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + SectionHeader( + leading: SizedBox(width: 12), + title: Text('Individual private campaigns'), + ), + VoicesDrawerNavItem( + name: 'Fund name 1', + status: ProposalStatus.ready, + ), + VoicesDrawerNavItem( + name: 'Campaign 1', + status: ProposalStatus.draft, + ), + VoicesDrawerNavItem( + name: 'What happens with a campaign title that is longer that', + status: ProposalStatus.draft, + ), + ], + ); + } +} diff --git a/catalyst_voices/lib/pages/spaces/spaces_drawer.dart b/catalyst_voices/lib/pages/spaces/spaces_drawer.dart new file mode 100644 index 00000000000..55c7b9a8083 --- /dev/null +++ b/catalyst_voices/lib/pages/spaces/spaces_drawer.dart @@ -0,0 +1,102 @@ +import 'package:catalyst_voices/pages/spaces/individual_private_campaigns.dart'; +import 'package:catalyst_voices/routes/routes.dart'; +import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices_brands/catalyst_voices_brands.dart'; +import 'package:catalyst_voices_localization/catalyst_voices_localization.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:flutter/material.dart'; + +class SpacesDrawer extends StatelessWidget { + final Space space; + + const SpacesDrawer({ + required this.space, + }); + + @override + Widget build(BuildContext context) { + return VoicesDrawer( + children: [ + _SpaceHeader(space), + if (space == Space.treasury) IndividualPrivateCampaigns(), + ], + bottom: VoicesDrawerSpaceChooser( + currentSpace: space, + onChanged: (space) { + Scaffold.of(context).closeDrawer(); + _goTo(context, space: space); + }, + ), + ); + } + + void _goTo( + BuildContext context, { + required Space space, + }) { + switch (space) { + case Space.treasury: + TreasuryRoute().go(context); + case Space.discovery: + DiscoveryRoute().go(context); + case Space.workspace: + WorkspaceRoute().go(context); + case Space.voting: + VotingRoute().go(context); + case Space.fundedProjects: + FundedProjectsRoute().go(context); + } + } +} + +// Note. This should be dropdown bo at the moment we're not +// implementing it. +class _SpaceHeader extends StatelessWidget { + final Space data; + + const _SpaceHeader(this.data); + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Container( + padding: + EdgeInsets.symmetric(vertical: 14).add(EdgeInsets.only(left: 16)), + child: Row( + children: [ + SpaceAvatar( + data, + key: ObjectKey(data), + ), + SizedBox(width: 12), + Expanded( + child: Text( + data.localizedName(context.l10n), + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: theme.textTheme.titleMedium + ?.copyWith(color: theme.colors.textPrimary), + ), + ), + ChevronExpandButton( + isExpanded: false, + onTap: () {}, + ), + ], + ), + ); + } +} + +extension _SpaceExt on Space { + String localizedName(VoicesLocalizations localizations) { + return switch (this) { + Space.treasury => localizations.drawerSpaceTreasury, + Space.discovery => localizations.drawerSpaceDiscovery, + Space.workspace => localizations.drawerSpaceWorkspace, + Space.voting => localizations.drawerSpaceVoting, + Space.fundedProjects => localizations.drawerSpaceFundedProjects, + }; + } +} diff --git a/catalyst_voices/lib/pages/spaces/spaces_shell_page.dart b/catalyst_voices/lib/pages/spaces/spaces_shell_page.dart index aaf098869e7..44e4977a2fe 100644 --- a/catalyst_voices/lib/pages/spaces/spaces_shell_page.dart +++ b/catalyst_voices/lib/pages/spaces/spaces_shell_page.dart @@ -1,4 +1,4 @@ -import 'package:catalyst_voices/routes/routes.dart'; +import 'package:catalyst_voices/pages/spaces/spaces_drawer.dart'; import 'package:catalyst_voices/widgets/widgets.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; @@ -17,48 +17,8 @@ class SpacesShellPage extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: VoicesAppBar(), - drawer: _SpacesDrawer(space: space), + drawer: SpacesDrawer(space: space), body: child, ); } } - -class _SpacesDrawer extends StatelessWidget { - final Space space; - - const _SpacesDrawer({ - required this.space, - }); - - @override - Widget build(BuildContext context) { - return VoicesDrawer( - children: [], - bottom: VoicesDrawerSpaceChooser( - currentSpace: space, - onChanged: (space) { - Scaffold.of(context).closeDrawer(); - _goTo(context, space: space); - }, - ), - ); - } - - void _goTo( - BuildContext context, { - required Space space, - }) { - switch (space) { - case Space.treasury: - TreasuryRoute().go(context); - case Space.discovery: - DiscoveryRoute().go(context); - case Space.workspace: - WorkspaceRoute().go(context); - case Space.voting: - VotingRoute().go(context); - case Space.fundedProjects: - FundedProjectsRoute().go(context); - } - } -} diff --git a/catalyst_voices/lib/widgets/avatars/space_avatar.dart b/catalyst_voices/lib/widgets/avatars/space_avatar.dart new file mode 100644 index 00000000000..1956e0c0a21 --- /dev/null +++ b/catalyst_voices/lib/widgets/avatars/space_avatar.dart @@ -0,0 +1,86 @@ +import 'package:catalyst_voices/widgets/widgets.dart'; +import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; +import 'package:catalyst_voices_brands/catalyst_voices_brands.dart'; +import 'package:catalyst_voices_models/catalyst_voices_models.dart'; +import 'package:flutter/material.dart'; + +/// Widget for [Space] [VoicesAvatar] adaptation. +class SpaceAvatar extends StatelessWidget { + final Space data; + + /// See [VoicesAvatar.onTap]. + final VoidCallback? onTap; + + /// See [VoicesAvatar.padding]. + final EdgeInsets padding; + + /// See [VoicesAvatar.radius]. + final double radius; + + const SpaceAvatar( + this.data, { + super.key, + this.onTap, + this.padding = const EdgeInsets.all(8), + this.radius = 20, + }); + + @override + Widget build(BuildContext context) { + final config = data._config(context); + + return VoicesAvatar( + icon: Icon(config.iconData), + backgroundColor: config.backgroundColor, + foregroundColor: config.foregroundColor, + padding: padding, + radius: radius, + ); + } +} + +final class _SpaceAvatarConfig { + final IconData iconData; + final Color backgroundColor; + final Color foregroundColor; + + _SpaceAvatarConfig({ + required this.iconData, + required this.backgroundColor, + required this.foregroundColor, + }); +} + +extension _SpaceExt on Space { + _SpaceAvatarConfig _config(BuildContext context) { + final theme = Theme.of(context); + + return switch (this) { + Space.treasury => _SpaceAvatarConfig( + iconData: CatalystVoicesIcons.fund, + backgroundColor: theme.colors.successContainer!, + foregroundColor: theme.colors.iconsSuccess!, + ), + Space.discovery => _SpaceAvatarConfig( + iconData: CatalystVoicesIcons.light_bulb, + backgroundColor: theme.colors.iconsSecondary!.withOpacity(0.16), + foregroundColor: theme.colors.iconsSecondary!, + ), + Space.workspace => _SpaceAvatarConfig( + iconData: CatalystVoicesIcons.briefcase, + backgroundColor: theme.colorScheme.primaryContainer, + foregroundColor: theme.colorScheme.primary, + ), + Space.voting => _SpaceAvatarConfig( + iconData: CatalystVoicesIcons.vote, + backgroundColor: theme.colors.warningContainer!, + foregroundColor: theme.colors.iconsWarning!, + ), + Space.fundedProjects => _SpaceAvatarConfig( + iconData: CatalystVoicesIcons.flag, + backgroundColor: theme.colors.iconsSecondary!.withOpacity(0.16), + foregroundColor: theme.colors.iconsSecondary!, + ), + }; + } +} diff --git a/catalyst_voices/lib/widgets/drawer/voices_drawer_space_chooser.dart b/catalyst_voices/lib/widgets/drawer/voices_drawer_space_chooser.dart index 3ae36fb488d..1e4e7393bfe 100644 --- a/catalyst_voices/lib/widgets/drawer/voices_drawer_space_chooser.dart +++ b/catalyst_voices/lib/widgets/drawer/voices_drawer_space_chooser.dart @@ -1,6 +1,6 @@ +import 'package:catalyst_voices/widgets/avatars/space_avatar.dart'; import 'package:catalyst_voices/widgets/drawer/voices_drawer.dart'; import 'package:catalyst_voices_assets/catalyst_voices_assets.dart'; -import 'package:catalyst_voices_brands/catalyst_voices_brands.dart'; import 'package:catalyst_voices_models/catalyst_voices_models.dart'; import 'package:flutter/material.dart'; @@ -34,61 +34,12 @@ class VoicesDrawerSpaceChooser extends StatelessWidget { required bool isSelected, }) { if (isSelected) { - final config = item._config(context); - - return VoicesDrawerChooserItem( - icon: config.iconData, - foregroundColor: config.foregroundColor, - backgroundColor: config.backgroundColor, + return SpaceAvatar( + item, + key: ValueKey('DrawerChooser${item}AvatarKey'), ); } else { return const VoicesDrawerChooserItemPlaceholder(); } } } - -final class _VoicesDrawerSpaceChooserConfig { - final IconData iconData; - final Color backgroundColor; - final Color foregroundColor; - - _VoicesDrawerSpaceChooserConfig({ - required this.iconData, - required this.backgroundColor, - required this.foregroundColor, - }); -} - -extension _SpaceExt on Space { - _VoicesDrawerSpaceChooserConfig _config(BuildContext context) { - final theme = Theme.of(context); - - return switch (this) { - Space.treasury => _VoicesDrawerSpaceChooserConfig( - iconData: CatalystVoicesIcons.fund, - backgroundColor: theme.colors.successContainer!, - foregroundColor: theme.colors.iconsSuccess!, - ), - Space.discovery => _VoicesDrawerSpaceChooserConfig( - iconData: CatalystVoicesIcons.light_bulb, - backgroundColor: theme.colors.iconsSecondary!.withOpacity(0.16), - foregroundColor: theme.colors.iconsSecondary!, - ), - Space.workspace => _VoicesDrawerSpaceChooserConfig( - iconData: CatalystVoicesIcons.briefcase, - backgroundColor: theme.colorScheme.primaryContainer, - foregroundColor: theme.colorScheme.primary, - ), - Space.voting => _VoicesDrawerSpaceChooserConfig( - iconData: CatalystVoicesIcons.vote, - backgroundColor: theme.colors.warningContainer!, - foregroundColor: theme.colors.iconsWarning!, - ), - Space.fundedProjects => _VoicesDrawerSpaceChooserConfig( - iconData: CatalystVoicesIcons.flag, - backgroundColor: theme.colors.iconsSecondary!.withOpacity(0.16), - foregroundColor: theme.colors.iconsSecondary!, - ), - }; - } -} diff --git a/catalyst_voices/lib/widgets/widgets.dart b/catalyst_voices/lib/widgets/widgets.dart index 9e55ddc7b68..3c4d945fb16 100644 --- a/catalyst_voices/lib/widgets/widgets.dart +++ b/catalyst_voices/lib/widgets/widgets.dart @@ -1,4 +1,5 @@ export 'app_bar/voices_app_bar.dart'; +export 'avatars/space_avatar.dart'; export 'avatars/voices_avatar.dart'; export 'buttons/voices_buttons.dart'; export 'buttons/voices_filled_button.dart'; 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 adaabe76f1d..603c478311d 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 @@ -447,6 +447,36 @@ abstract class VoicesLocalizations { /// In en, this message translates to: /// **'Edit'** String get treasuryStepEdit; + + /// Name shown in spaces shell drawer + /// + /// In en, this message translates to: + /// **'Treasury'** + String get drawerSpaceTreasury; + + /// Name shown in spaces shell drawer + /// + /// In en, this message translates to: + /// **'Discovery'** + String get drawerSpaceDiscovery; + + /// Name shown in spaces shell drawer + /// + /// In en, this message translates to: + /// **'Workspace'** + String get drawerSpaceWorkspace; + + /// Name shown in spaces shell drawer + /// + /// In en, this message translates to: + /// **'Voting'** + String get drawerSpaceVoting; + + /// Name shown in spaces shell drawer + /// + /// In en, this message translates to: + /// **'Funded projects'** + String get drawerSpaceFundedProjects; } 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 2ccde898c07..788f77d670c 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 @@ -235,4 +235,19 @@ class VoicesLocalizationsEn extends VoicesLocalizations { @override String get treasuryStepEdit => 'Edit'; + + @override + String get drawerSpaceTreasury => 'Treasury'; + + @override + String get drawerSpaceDiscovery => 'Discovery'; + + @override + String get drawerSpaceWorkspace => 'Workspace'; + + @override + String get drawerSpaceVoting => 'Voting'; + + @override + String get drawerSpaceFundedProjects => 'Funded projects'; } 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 869ac1fcde8..d2689af3d26 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 @@ -235,4 +235,19 @@ class VoicesLocalizationsEs extends VoicesLocalizations { @override String get treasuryStepEdit => 'Edit'; + + @override + String get drawerSpaceTreasury => 'Treasury'; + + @override + String get drawerSpaceDiscovery => 'Discovery'; + + @override + String get drawerSpaceWorkspace => 'Workspace'; + + @override + String get drawerSpaceVoting => 'Voting'; + + @override + String get drawerSpaceFundedProjects => 'Funded projects'; } 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 18b2898f87f..7416217c202 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 @@ -276,5 +276,25 @@ "treasuryStepEdit": "Edit", "@treasuryStepEdit": { "description": "Button name in treasury step" + }, + "drawerSpaceTreasury": "Treasury", + "@drawerSpaceTreasury": { + "description": "Name shown in spaces shell drawer" + }, + "drawerSpaceDiscovery": "Discovery", + "@drawerSpaceDiscovery": { + "description": "Name shown in spaces shell drawer" + }, + "drawerSpaceWorkspace": "Workspace", + "@drawerSpaceWorkspace": { + "description": "Name shown in spaces shell drawer" + }, + "drawerSpaceVoting": "Voting", + "@drawerSpaceVoting": { + "description": "Name shown in spaces shell drawer" + }, + "drawerSpaceFundedProjects": "Funded projects", + "@drawerSpaceFundedProjects": { + "description": "Name shown in spaces shell drawer" } } \ No newline at end of file diff --git a/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_builder.dart b/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_builder.dart index 76763d6acbf..5951ba22b49 100644 --- a/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_builder.dart +++ b/catalyst_voices/packages/catalyst_voices_models/lib/src/treasury/treasury_campaign_builder.dart @@ -2,12 +2,12 @@ import 'package:catalyst_voices_models/src/treasury/treasury_campaign_segment.da import 'package:equatable/equatable.dart'; final class TreasuryCampaignBuilder extends Equatable { + final List segments; + TreasuryCampaignBuilder({ required this.segments, }); - final List segments; - @override List get props => [ segments, From 9ff30defdca710011ce4c00d7061048bcbf6999c Mon Sep 17 00:00:00 2001 From: Damian Molinski Date: Tue, 10 Sep 2024 11:09:09 +0200 Subject: [PATCH 8/8] refactor: rename builder function --- .../lib/pages/treasury/campaign_segment_controller.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/catalyst_voices/lib/pages/treasury/campaign_segment_controller.dart b/catalyst_voices/lib/pages/treasury/campaign_segment_controller.dart index 4cff5ba27db..da062474189 100644 --- a/catalyst_voices/lib/pages/treasury/campaign_segment_controller.dart +++ b/catalyst_voices/lib/pages/treasury/campaign_segment_controller.dart @@ -1,9 +1,7 @@ import 'package:catalyst_voices/widgets/menu/voices_node_menu.dart'; import 'package:flutter/material.dart'; -typedef ControllerBuilder = CampaignController Function( - Object segmentId, -); +typedef CampaignControllerBuilder = CampaignController Function(Object id); final class CampaignControllerStateData extends VoicesNodeMenuStateData { const CampaignControllerStateData({ @@ -20,7 +18,7 @@ final class CampaignController extends VoicesNodeMenuController { /// Keeps together [CampaignControllerStateData] tied to ids. class CampaignControllerScope extends StatefulWidget { - final ControllerBuilder builder; + final CampaignControllerBuilder builder; final Widget child; const CampaignControllerScope({