Skip to content

Commit 5bf67f6

Browse files
feat(cat-voices): voting space (#3648)
* docs: capture initial times * chore: remove cacheDocument * turn off logging * chore: use debugPrint instead of logger * feat: bulk documents save * batching sync * chore: move exact ref resoling to getDocumentData instead of index * fix: DocumentRepository * chore: simplify getting documents data * remove getAllDocumentsRefs and getCachedDocumentsRefs from DocumentRepository. Index is only available in DocumentDataRemoteSource * chore: update docs * simplified document index endpoint * remove randomness from LocalCatGateway * indexing by batch size * wip: filtering by types * Rework filtering refs + checking all refs if already cached in parallel * docs * update indexing.csv * update indexing csv * chore: cleanup * trailing new line * chore * move performance tab to docs * bulk saving typed docs in parallel * chore: revert hardcoded timestamp * chore: typos * split _sync into smaller functions + add documentation * little refactor * fix: analyzer * initial v2 tables * wip * wip * feat: database migration * chore: cleanup * bump batch size * cleanup * chore: remove defensive content decoding * chore: daos * spelling * saveAll * test on platform * chore: update build scripts * feat: DocumentsV2Dao methods * simple proposals pagination query * chore: create a JoinedProposalBriefEntity * rename method * feat: exclude hidden proposals * more tests * renaming and splitting logic into smaller parts * feat: per language strategy * remove CatalystDatabaseLanguage in favor of raw queries as they are easier to mange * remove Index Strategy Documentation * handle case where ref is empty * migration now includes indexes * use v2 documents table for saveAll and isCachedBulk * adds ActionType to JoinedProposalBriefEntity * adds versionIds to JoinedProposalBriefEntity * comments count * adds isFavorite to JoinedProposalBriefEntity * add template to JoinedProposalBriefEntity * adds documentsLocalMetadata table for auto updates * Update docs * use v2 proposals query for discovery most recent section * feat: simplify most recent proposals section * add proposal fav status for v2 tables * local proposal fav status update * update fav state locally for faster feedback * self review * fix tests * update times * fix: analyzer * more migration test data * clean up constructors * cleanup * fix: template tests * spelling * fix: spelling * chore: PR review adjustments * add order parameter * ProposalsOrder docs * GetProposalsBriefPage supports order * add filters object * proposalsBriefPage filtering * fix: status filtering * more draft proposals filtering tests * Campaign proposals filter * update docs * expose getVisibleProposalsCount and tests * expose filters parameter * integrate proposals page with v2 queries * chore: increase time diff between proposals * chore: reduce count query tables watched when not needed * local proposals cubit * local proposal fav staus update * docs * fix: add discovery specific colors (#3637) * fix code-generator earthly target * use logger in migration + wrap in transaction * spelling * wip * rename category to categoryId for better consistency * adding vote data to ProposalBriefData * fix: dependencies * voting page + cubit integration - wip * proposals per tab selector * release completed in close * extract early return logic into function * Voting tabs selector + releasing completer on close * move spaces blocs to shell page level * fix: voting in grid view * dummy voting integration * chore: remove showComments * docs: ProposalOrDocument --------- Co-authored-by: Ryszard Schossler <[email protected]>
1 parent 0ce951e commit 5bf67f6

File tree

36 files changed

+716
-609
lines changed

36 files changed

+716
-609
lines changed

catalyst_voices/apps/voices/lib/app/view/app.dart

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,9 @@ class _AppState extends State<App> {
4747
BlocProvider<SessionCubit>(
4848
create: (_) => Dependencies.instance.get<SessionCubit>(),
4949
),
50-
BlocProvider<VotingCubit>(
51-
create: (_) => Dependencies.instance.get<VotingCubit>(),
52-
),
5350
BlocProvider<CampaignBuilderCubit>(
5451
create: (_) => Dependencies.instance.get<CampaignBuilderCubit>(),
5552
),
56-
BlocProvider<WorkspaceBloc>(
57-
create: (context) => Dependencies.instance.get<WorkspaceBloc>(),
58-
),
59-
BlocProvider<DiscoveryCubit>(
60-
create: (context) => Dependencies.instance.get<DiscoveryCubit>(),
61-
),
6253
BlocProvider<CategoryDetailCubit>(
6354
create: (_) => Dependencies.instance.get<CategoryDetailCubit>(),
6455
),

catalyst_voices/apps/voices/lib/dependency/dependencies.dart

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,11 @@ final class Dependencies extends DependencyProvider {
120120
get<ProposalService>(),
121121
),
122122
)
123-
..registerLazySingleton<VotingCubit>(
123+
..registerFactory<VotingCubit>(
124124
() => VotingCubit(
125125
get<UserService>(),
126126
get<CampaignService>(),
127127
get<ProposalService>(),
128-
get<VotingBallotBuilder>(),
129-
get<VotingService>(),
130128
),
131129
)
132130
// TODO(LynxLynxx): add repository for campaign management
@@ -400,6 +398,7 @@ final class Dependencies extends DependencyProvider {
400398
get<SignerService>(),
401399
get<ActiveCampaignObserver>(),
402400
get<CastedVotesObserver>(),
401+
get<VotingBallotBuilder>(),
403402
);
404403
});
405404
registerLazySingleton<CommentService>(() {
@@ -536,7 +535,10 @@ final class Dependencies extends DependencyProvider {
536535
dispose: (observer) async => observer.dispose(),
537536
);
538537
registerLazySingleton<CastedVotesObserver>(CastedVotesObserverImpl.new);
539-
registerLazySingleton<VotingBallotBuilder>(VotingBallotLocalBuilder.new);
538+
registerLazySingleton<VotingBallotBuilder>(
539+
VotingBallotLocalBuilder.new,
540+
dispose: (builder) => builder.dispose(),
541+
);
540542

541543
// Not a singleton
542544
registerFactory<RegistrationStatusPoller>(

catalyst_voices/apps/voices/lib/pages/discovery/sections/most_recent_proposals/widgets/most_recent_proposals_list.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ class MostRecentProposalsList extends StatelessWidget {
2323
return _MostRecentProposalsList(
2424
scrollController: scrollController,
2525
proposals: state.proposals,
26-
showComments: state.showComments,
2726
);
2827
},
2928
);
@@ -32,12 +31,10 @@ class MostRecentProposalsList extends StatelessWidget {
3231

3332
class _MostRecentProposalsList extends StatelessWidget {
3433
final List<ProposalBrief> proposals;
35-
final bool showComments;
3634
final ScrollController? scrollController;
3735

3836
const _MostRecentProposalsList({
3937
required this.proposals,
40-
required this.showComments,
4138
this.scrollController,
4239
});
4340

@@ -58,7 +55,6 @@ class _MostRecentProposalsList extends StatelessWidget {
5855
proposal: proposal,
5956
onTap: () => _onCardTap(context, ref),
6057
onFavoriteChanged: (value) => _onCardFavoriteChanged(context, ref, value),
61-
showComments: showComments,
6258
),
6359
);
6460
},
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import 'package:catalyst_voices/dependency/dependencies.dart';
2+
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
3+
import 'package:flutter/material.dart';
4+
5+
class SpacesShellBlocProvider extends StatelessWidget {
6+
final Widget child;
7+
8+
const SpacesShellBlocProvider({
9+
super.key,
10+
required this.child,
11+
});
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return MultiBlocProvider(
16+
providers: [
17+
BlocProvider<VotingCubit>(
18+
create: (_) => Dependencies.instance.get<VotingCubit>(),
19+
),
20+
BlocProvider<WorkspaceBloc>(
21+
create: (context) => Dependencies.instance.get<WorkspaceBloc>(),
22+
),
23+
BlocProvider<DiscoveryCubit>(
24+
create: (context) => Dependencies.instance.get<DiscoveryCubit>(),
25+
),
26+
],
27+
child: child,
28+
);
29+
}
30+
}

catalyst_voices/apps/voices/lib/pages/spaces/spaces_shell_page.dart

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:catalyst_voices/pages/campaign/admin_tools/campaign_admin_tools_
55
import 'package:catalyst_voices/pages/spaces/appbar/spaces_appbar.dart';
66
import 'package:catalyst_voices/pages/spaces/drawer/spaces_drawer.dart';
77
import 'package:catalyst_voices/pages/spaces/drawer/spaces_end_drawer.dart';
8+
import 'package:catalyst_voices/pages/spaces/spaces_shell_bloc_provider.dart';
89
import 'package:catalyst_voices_blocs/catalyst_voices_blocs.dart';
910
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
1011
import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart';
@@ -65,40 +66,42 @@ class _SpacesShellPageState extends State<SpacesShellPage> {
6566

6667
@override
6768
Widget build(BuildContext context) {
68-
return BlocListener<AdminToolsCubit, AdminToolsState>(
69-
listenWhen: (previous, current) => previous.enabled != current.enabled,
70-
listener: (context, state) {
71-
if (state.enabled) {
72-
_insertAdminToolsOverlay();
73-
} else {
74-
_removeAdminToolsOverlay();
75-
}
76-
},
77-
child: _Shortcuts(
78-
onToggleAdminTools: _toggleAdminTools,
79-
child: BlocSelector<SessionCubit, SessionState, _SessionStateData>(
80-
selector: (state) => (
81-
isActive: state.isActive,
82-
isProposer: state.account?.isProposer ?? false,
69+
return SpacesShellBlocProvider(
70+
child: BlocListener<AdminToolsCubit, AdminToolsState>(
71+
listenWhen: (previous, current) => previous.enabled != current.enabled,
72+
listener: (context, state) {
73+
if (state.enabled) {
74+
_insertAdminToolsOverlay();
75+
} else {
76+
_removeAdminToolsOverlay();
77+
}
78+
},
79+
child: _Shortcuts(
80+
onToggleAdminTools: _toggleAdminTools,
81+
child: BlocSelector<SessionCubit, SessionState, _SessionStateData>(
82+
selector: (state) => (
83+
isActive: state.isActive,
84+
isProposer: state.account?.isProposer ?? false,
85+
),
86+
builder: (context, state) {
87+
return Scaffold(
88+
appBar: SpacesAppbar(
89+
space: widget.space,
90+
isAppUnlock: state.isActive,
91+
isProposer: state.isProposer,
92+
),
93+
drawer: state.isActive
94+
? SpacesDrawer(
95+
space: widget.space,
96+
spacesShortcutsActivators: AccessControl.allSpacesShortcutsActivators,
97+
isUnlocked: state.isActive,
98+
)
99+
: null,
100+
endDrawer: SpacesEndDrawer(space: widget.space),
101+
body: widget.child,
102+
);
103+
},
83104
),
84-
builder: (context, state) {
85-
return Scaffold(
86-
appBar: SpacesAppbar(
87-
space: widget.space,
88-
isAppUnlock: state.isActive,
89-
isProposer: state.isProposer,
90-
),
91-
drawer: state.isActive
92-
? SpacesDrawer(
93-
space: widget.space,
94-
spacesShortcutsActivators: AccessControl.allSpacesShortcutsActivators,
95-
isUnlocked: state.isActive,
96-
)
97-
: null,
98-
endDrawer: SpacesEndDrawer(space: widget.space),
99-
body: widget.child,
100-
);
101-
},
102105
),
103106
),
104107
);
@@ -120,12 +123,6 @@ class _SpacesShellPageState extends State<SpacesShellPage> {
120123
super.dispose();
121124
}
122125

123-
@override
124-
void initState() {
125-
super.initState();
126-
context.read<WorkspaceBloc>().add(const WatchUserProposalsEvent());
127-
}
128-
129126
OverlayEntry _createAdminToolsOverlay() {
130127
return OverlayEntry(
131128
builder: (BuildContext context) {

catalyst_voices/apps/voices/lib/pages/voting/voting_page.dart

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import 'package:flutter/material.dart';
1919
import 'package:rxdart/rxdart.dart';
2020

2121
class VotingPage extends StatefulWidget {
22-
final SignedDocumentRef? categoryId;
22+
final String? categoryId;
2323
final VotingPageTab? tab;
2424

2525
const VotingPage({
@@ -38,7 +38,7 @@ class _VotingPageState extends State<VotingPage>
3838
ErrorHandlerStateMixin<VotingCubit, VotingPage>,
3939
SignalHandlerStateMixin<VotingCubit, VotingSignal, VotingPage> {
4040
late VoicesTabController<VotingPageTab> _tabController;
41-
late final PagingController<ProposalBriefVoting> _pagingController;
41+
late final PagingController<ProposalBrief> _pagingController;
4242
late final StreamSubscription<List<VotingPageTab>> _tabsSubscription;
4343

4444
@override
@@ -78,9 +78,8 @@ class _VotingPageState extends State<VotingPage>
7878

7979
if (widget.categoryId != oldWidget.categoryId || widget.tab != oldWidget.tab) {
8080
context.read<VotingCubit>().changeFilters(
81-
onlyMy: Optional(tab == VotingPageTab.my),
82-
category: Optional(widget.categoryId),
83-
type: tab.filter,
81+
categoryId: Optional(widget.categoryId),
82+
tab: Optional(tab),
8483
);
8584

8685
_doResetPagination();
@@ -103,7 +102,7 @@ class _VotingPageState extends State<VotingPage>
103102
void handleSignal(VotingSignal signal) {
104103
switch (signal) {
105104
case ChangeCategoryVotingSignal(:final to):
106-
_updateRoute(categoryId: Optional(to?.id));
105+
_updateRoute(categoryId: Optional(to));
107106
case ChangeTabVotingSignal(:final tab):
108107
_updateRoute(tab: tab);
109108
case ResetPaginationVotingSignal():
@@ -146,9 +145,8 @@ class _VotingPageState extends State<VotingPage>
146145
).distinct().listen(_updateTabsIfNeeded);
147146

148147
votingCubit.init(
149-
onlyMyProposals: selectedTab == VotingPageTab.my,
150-
category: widget.categoryId,
151-
type: selectedTab.filter,
148+
categoryId: widget.categoryId,
149+
tab: selectedTab,
152150
);
153151

154152
_pagingController
@@ -181,7 +179,7 @@ class _VotingPageState extends State<VotingPage>
181179
Future<void> _handleProposalsPageRequest(
182180
int pageKey,
183181
int pageSize,
184-
ProposalBriefVoting? lastProposalId,
182+
ProposalBrief? lastProposalId,
185183
) async {
186184
final request = PageRequest(page: pageKey, size: pageSize);
187185
await context.read<VotingCubit>().getProposals(request);
@@ -192,7 +190,7 @@ class _VotingPageState extends State<VotingPage>
192190
VotingPageTab? tab,
193191
}) {
194192
Router.neglect(context, () {
195-
final effectiveCategoryId = categoryId.dataOr(widget.categoryId?.id);
193+
final effectiveCategoryId = categoryId.dataOr(widget.categoryId);
196194
final effectiveTab = tab?.name ?? widget.tab?.name;
197195

198196
VotingRoute(

catalyst_voices/apps/voices/lib/pages/voting/widgets/content/voting_content.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import 'package:flutter/material.dart';
1010

1111
class VotingContent extends StatelessWidget {
1212
final VoicesTabController<VotingPageTab> tabController;
13-
final PagingController<ProposalBriefVoting> pagingController;
13+
final PagingController<ProposalBrief> pagingController;
1414

1515
const VotingContent({
1616
super.key,

catalyst_voices/apps/voices/lib/pages/voting/widgets/grid/voting_proposals_pagination.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart';
77
import 'package:flutter/material.dart';
88

99
class VotingProposalsPagination extends StatelessWidget {
10-
final PagingController<ProposalBriefVoting> controller;
10+
final PagingController<ProposalBrief> controller;
1111

1212
const VotingProposalsPagination({
1313
super.key,
@@ -16,9 +16,9 @@ class VotingProposalsPagination extends StatelessWidget {
1616

1717
@override
1818
Widget build(BuildContext context) {
19-
return PaginatedGridView<ProposalBriefVoting>(
19+
return PaginatedGridView<ProposalBrief>(
2020
pagingController: controller,
21-
builderDelegate: PagedWrapChildBuilder<ProposalBriefVoting>(
21+
builderDelegate: PagedWrapChildBuilder<ProposalBrief>(
2222
builder: (context, item) {
2323
return VotingProposalsPaginationTile(
2424
key: ValueKey(item.selfRef),

catalyst_voices/apps/voices/lib/pages/voting/widgets/grid/voting_proposals_pagination_tile.dart

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import 'package:catalyst_voices_view_models/catalyst_voices_view_models.dart';
77
import 'package:flutter/material.dart';
88

99
class VotingProposalsPaginationTile extends StatelessWidget {
10-
final ProposalBriefVoting proposal;
10+
final ProposalBrief proposal;
1111

1212
const VotingProposalsPaginationTile({
1313
super.key,
@@ -24,9 +24,11 @@ class VotingProposalsPaginationTile extends StatelessWidget {
2424
unawaited(route.push(context));
2525
},
2626
onFavoriteChanged: (isFavorite) {
27-
context.read<VotingCubit>().onChangeFavoriteProposal(
28-
proposal.selfRef,
29-
isFavorite: isFavorite,
27+
unawaited(
28+
context.read<VotingCubit>().onChangeFavoriteProposal(
29+
proposal.selfRef,
30+
isFavorite: isFavorite,
31+
),
3032
);
3133
},
3234
onVoteAction: (action) {
@@ -38,7 +40,6 @@ class VotingProposalsPaginationTile extends StatelessWidget {
3840

3941
context.read<VotingBallotBloc>().add(event);
4042
},
41-
readOnly: true,
4243
);
4344
}
4445
}

0 commit comments

Comments
 (0)