Skip to content

Commit f21f815

Browse files
feat(cat-voices): proposal details integration - Part 2 (#2090)
* feat: watching active account + rename some parent fields to reply * feat: proposal error and loading states * chore: integrate loading ProposalDocument * chore: safe check finally state change * refactor: ProposalCubit cache extracted into a object * feat: CommentService * refactor: move credentials logic to separate service * chore: DocumentDataMetadata reply and section fields * chore: TODO for later * feat: CommentService and Repository * chore: add refTo filter * feat: building comment with replies tree * refactor: make canReply list item argument * feat: publish a comment * test: comment template fixture * chore: hide comments segment when cannot comment or has no comments * fix: removing local failed comments * chore: comments list items spacings * chore: hide sort comments when empty * fix: missing comment template ref * chore: saving comment after publishing * chore: adjust publish comment document metadata * fix: nesting replies * feat: filter out category node from proposal view * refactor: move document props getters to ProposalDocument * feat: integrate ProposalDocumentDetails * feat: make rotation a parameter * chore: PR review adjustments * refactor: use Coin.fromWholeAda
1 parent 1aada6f commit f21f815

File tree

12 files changed

+185
-119
lines changed

12 files changed

+185
-119
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ final class Dependencies extends DependencyProvider {
128128
get<UserService>(),
129129
get<ProposalService>(),
130130
get<CommentService>(),
131+
get<CampaignService>(),
131132
get<DocumentMapper>(),
132133
);
133134
})

catalyst_voices/apps/voices/lib/pages/proposal/tiles/proposal_metadata_tile.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart';
12
import 'package:catalyst_voices/common/ext/build_context_ext.dart';
23
import 'package:catalyst_voices/pages/proposal/widget/proposal_delivery_card.dart';
34
import 'package:catalyst_voices/pages/proposal/widget/proposal_version.dart';
@@ -18,9 +19,9 @@ class ProposalMetadataTile extends StatelessWidget {
1819
final bool warningCreatedAt;
1920
final String? tag;
2021
final int commentsCount;
21-
final int fundsRequested;
22-
final int projectDuration;
23-
final int milestoneCount;
22+
final Coin? fundsRequested;
23+
final int? projectDuration;
24+
final int? milestoneCount;
2425

2526
const ProposalMetadataTile({
2627
super.key,

catalyst_voices/apps/voices/lib/pages/proposal/widget/proposal_delivery_card.dart

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import 'package:catalyst_cardano_serialization/catalyst_cardano_serialization.dart';
12
import 'package:catalyst_voices/common/ext/build_context_ext.dart';
23
import 'package:catalyst_voices_localization/catalyst_voices_localization.dart';
3-
import 'package:catalyst_voices_models/catalyst_voices_models.dart';
4+
import 'package:catalyst_voices_shared/catalyst_voices_shared.dart';
45
import 'package:flutter/material.dart';
56

67
class ProposalDeliveryCard extends StatelessWidget {
7-
final int fundsRequested;
8-
final int projectDuration;
9-
final int milestoneCount;
8+
final Coin? fundsRequested;
9+
final int? projectDuration;
10+
final int? milestoneCount;
1011

1112
const ProposalDeliveryCard({
1213
super.key,
@@ -17,6 +18,10 @@ class ProposalDeliveryCard extends StatelessWidget {
1718

1819
@override
1920
Widget build(BuildContext context) {
21+
final fundsRequested = this.fundsRequested;
22+
final projectDuration = this.projectDuration;
23+
final milestoneCount = this.milestoneCount;
24+
2025
return Container(
2126
width: double.infinity,
2227
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
@@ -30,30 +35,32 @@ class ProposalDeliveryCard extends StatelessWidget {
3035
alignment: WrapAlignment.spaceAround,
3136
runAlignment: WrapAlignment.center,
3237
children: [
33-
_ValueCell(
34-
title: context.l10n.proposalViewFundingRequested,
35-
value: '',
36-
valueSuffix: const Currency.ada().format(
37-
fundsRequested,
38-
separator: ' ',
38+
if (fundsRequested != null)
39+
_ValueCell(
40+
title: context.l10n.proposalViewFundingRequested,
41+
value: '',
42+
valueSuffix: CryptocurrencyFormatter.decimalFormat(
43+
fundsRequested,
44+
),
45+
),
46+
if (projectDuration != null)
47+
_ValueCell(
48+
title: context.l10n.proposalViewProjectDuration,
49+
value: context.l10n
50+
.valueMonths(projectDuration)
51+
.replaceAll('$projectDuration', '')
52+
.trim(),
53+
valueSuffix: '$projectDuration',
54+
),
55+
if (milestoneCount != null)
56+
_ValueCell(
57+
title: context.l10n.proposalViewProjectDelivery,
58+
value: context.l10n
59+
.valueMilestones(milestoneCount)
60+
.replaceAll('$milestoneCount', '')
61+
.trim(),
62+
valueSuffix: '$milestoneCount',
3963
),
40-
),
41-
_ValueCell(
42-
title: context.l10n.proposalViewProjectDuration,
43-
value: context.l10n
44-
.valueMonths(projectDuration)
45-
.replaceAll('$projectDuration', '')
46-
.trim(),
47-
valueSuffix: '$projectDuration',
48-
),
49-
_ValueCell(
50-
title: context.l10n.proposalViewProjectDelivery,
51-
value: context.l10n
52-
.valueMilestones(milestoneCount)
53-
.replaceAll('$milestoneCount', '')
54-
.trim(),
55-
valueSuffix: '$milestoneCount',
56-
),
5764
],
5865
),
5966
);

catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/document/document_to_segment_mixin.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,18 @@ mixin DocumentToSegmentMixin {
66
List<DocumentSegment> mapDocumentToSegments(
77
Document document, {
88
bool showValidationErrors = false,
9+
List<DocumentNodeId> filterOut = const [],
910
}) {
1011
final result = <DocumentSegment>[];
1112

12-
for (final segment in document.segments) {
13+
final effectiveSegments = document.segments
14+
.where((element) => !filterOut.contains(element.nodeId))
15+
.toList();
16+
17+
for (final segment in effectiveSegments) {
1318
final sections = segment.sections
1419
.expand(DocumentNodeTraverser.findSectionsAndSubsections)
20+
.where((element) => !filterOut.contains(element.nodeId))
1521
.map((section) {
1622
return DocumentSection(
1723
id: section.schema.nodeId,

catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal/proposal_cubit.dart

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ final class ProposalCubit extends Cubit<ProposalState>
2121
final UserService _userService;
2222
final ProposalService _proposalService;
2323
final CommentService _commentService;
24+
final CampaignService _campaignService;
2425
final DocumentMapper _documentMapper;
2526

2627
ProposalCubitCache _cache = const ProposalCubitCache();
@@ -32,6 +33,7 @@ final class ProposalCubit extends Cubit<ProposalState>
3233
this._userService,
3334
this._proposalService,
3435
this._commentService,
36+
this._campaignService,
3537
this._documentMapper,
3638
) : super(const ProposalState()) {
3739
_cache = _cache.copyWith(
@@ -63,6 +65,7 @@ final class ProposalCubit extends Cubit<ProposalState>
6365
emit(state.copyWith(isLoading: true));
6466

6567
final proposal = await _proposalService.getProposal(ref: ref);
68+
final category = await _campaignService.getCategory(proposal.categoryId);
6669
final commentTemplate = await _commentService.getCommentTemplateFor(
6770
category: proposal.categoryId,
6871
);
@@ -71,6 +74,7 @@ final class ProposalCubit extends Cubit<ProposalState>
7174

7275
_cache = _cache.copyWith(
7376
proposal: Optional(proposal),
77+
category: Optional(category),
7478
commentTemplate: Optional(commentTemplate),
7579
comments: const Optional([]),
7680
isFavorite: Optional(isFavorite),
@@ -248,6 +252,7 @@ final class ProposalCubit extends Cubit<ProposalState>
248252
ProposalViewData _buildProposalViewData({
249253
required bool hasActiveAccount,
250254
required ProposalData? proposal,
255+
required CampaignCategory? category,
251256
required List<CommentWithReplies> comments,
252257
required DocumentSchema? commentSchema,
253258
required ProposalCommentsSort commentsSort,
@@ -256,7 +261,6 @@ final class ProposalCubit extends Cubit<ProposalState>
256261
final proposalDocument = proposal?.document;
257262
final proposalDocumentRef = proposalDocument?.metadata.selfRef;
258263

259-
/* cSpell:disable */
260264
final proposalVersions = proposal?.versions ?? const [];
261265
final versions = proposalVersions.mapIndexed((index, version) {
262266
final ver = version.document.metadata.selfRef.version;
@@ -273,6 +277,7 @@ final class ProposalCubit extends Cubit<ProposalState>
273277
final segments = proposal != null
274278
? _buildSegments(
275279
proposal: proposal,
280+
category: category,
276281
version: currentVersion,
277282
comments: comments,
278283
commentSchema: commentSchema,
@@ -281,57 +286,58 @@ final class ProposalCubit extends Cubit<ProposalState>
281286
)
282287
: const <Segment>[];
283288

289+
final header = ProposalViewHeader(
290+
title: proposalDocument?.title ?? '',
291+
authorDisplayName: proposalDocument?.authorName ?? '',
292+
createdAt: proposalDocumentRef?.version?.tryDateTime,
293+
commentsCount: comments.length,
294+
versions: versions,
295+
isFavorite: isFavorite,
296+
);
297+
284298
return ProposalViewData(
285299
isCurrentVersionLatest: currentVersion?.isLatest,
286-
header: ProposalViewHeader(
287-
title: 'Project Mayhem: Freedom by Chaos',
288-
authorDisplayName: 'Tyler Durden',
289-
createdAt: DateTime.timestamp(),
290-
commentsCount: comments.length,
291-
versions: versions,
292-
isFavorite: isFavorite,
293-
),
300+
header: header,
294301
segments: segments,
295302
commentsSort: commentsSort,
296303
);
297-
/* cSpell:enable */
298304
}
299305

300-
/* cSpell:disable */
301306
List<Segment> _buildSegments({
302307
required ProposalData proposal,
308+
required CampaignCategory? category,
303309
required DocumentVersion? version,
304310
required List<CommentWithReplies> comments,
305311
required DocumentSchema? commentSchema,
306312
required ProposalCommentsSort commentsSort,
307313
required bool hasActiveAccount,
308314
}) {
309-
final isDraftProposal = proposal.document.metadata.selfRef is DraftRef;
315+
final document = proposal.document;
316+
final isDraftProposal = document.metadata.selfRef is DraftRef;
310317

311318
final overviewSegment = ProposalOverviewSegment.build(
312-
categoryName: 'Cardano Partners: Growth & Acceleration',
313-
proposalTitle: 'Project Mayhem: Freedom by Chaos',
319+
categoryName: category?.categoryName ?? '',
320+
proposalTitle: document.title ?? '',
314321
data: ProposalViewMetadata(
315322
author: Profile(catalystId: DummyCatalystIdFactory.create()),
316-
description: 'Project Mayhem is a disruptive initiative to dismantle '
317-
'societal hierarchies through acts of controlled chaos. '
318-
'By targeting oppressive systems like credit structures and '
319-
'consumerist propaganda, we empower individuals to reclaim their '
320-
'agency. This ?decentralised movement fosters self-replication, '
321-
'inspiring global action for liberation and a return to human '
322-
'authenticity.',
323+
description: document.description,
323324
status: ProposalStatus.draft,
324325
createdAt: version?.id.tryDateTime ?? DateTime.now(),
325326
warningCreatedAt: version?.isLatest == false,
326-
tag: 'Community Outreach',
327+
tag: document.tag,
327328
commentsCount: comments.length,
328-
fundsRequested: 200000,
329-
projectDuration: 12,
330-
milestoneCount: 3,
329+
fundsRequested: document.fundsRequested,
330+
projectDuration: document.duration,
331+
milestoneCount: document.milestoneCount,
331332
),
332333
);
333334

334-
final proposalSegments = mapDocumentToSegments(proposal.document.document);
335+
final proposalSegments = mapDocumentToSegments(
336+
document.document,
337+
filterOut: [
338+
ProposalDocument.categoryNodeId,
339+
],
340+
);
335341

336342
final canReply = !isDraftProposal && hasActiveAccount;
337343
final canComment = canReply && commentSchema != null;
@@ -372,10 +378,9 @@ final class ProposalCubit extends Cubit<ProposalState>
372378
emit(state.copyWith(data: _rebuildProposalState()));
373379
}
374380

375-
/* cSpell:enable */
376-
377381
ProposalViewData _rebuildProposalState() {
378382
final proposal = _cache.proposal;
383+
final category = _cache.category;
379384
final commentTemplate = _cache.commentTemplate;
380385
final comments = _cache.comments ?? const [];
381386
final commentsSort = state.data.commentsSort;
@@ -385,6 +390,7 @@ final class ProposalCubit extends Cubit<ProposalState>
385390
return _buildProposalViewData(
386391
hasActiveAccount: activeAccountId != null,
387392
proposal: proposal,
393+
category: category,
388394
comments: comments,
389395
commentSchema: commentTemplate?.schema,
390396
commentsSort: commentsSort,

catalyst_voices/packages/internal/catalyst_voices_blocs/lib/src/proposal/proposal_cubit_cache.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ final class ProposalCubitCache extends Equatable {
55
final CatalystId? activeAccountId;
66
final DocumentRef? ref;
77
final ProposalData? proposal;
8+
final CampaignCategory? category;
89
final CommentTemplate? commentTemplate;
910
final List<CommentWithReplies>? comments;
1011
final bool? isFavorite;
@@ -13,6 +14,7 @@ final class ProposalCubitCache extends Equatable {
1314
this.activeAccountId,
1415
this.ref,
1516
this.proposal,
17+
this.category,
1618
this.commentTemplate,
1719
this.comments,
1820
this.isFavorite,
@@ -23,6 +25,7 @@ final class ProposalCubitCache extends Equatable {
2325
activeAccountId,
2426
ref,
2527
proposal,
28+
category,
2629
commentTemplate,
2730
comments,
2831
isFavorite,
@@ -32,6 +35,7 @@ final class ProposalCubitCache extends Equatable {
3235
Optional<CatalystId>? activeAccountId,
3336
Optional<DocumentRef>? ref,
3437
Optional<ProposalData>? proposal,
38+
Optional<CampaignCategory>? category,
3539
Optional<CommentTemplate>? commentTemplate,
3640
Optional<List<CommentWithReplies>>? comments,
3741
Optional<bool>? isFavorite,
@@ -40,6 +44,7 @@ final class ProposalCubitCache extends Equatable {
4044
activeAccountId: activeAccountId.dataOr(this.activeAccountId),
4145
ref: ref.dataOr(this.ref),
4246
proposal: proposal.dataOr(this.proposal),
47+
category: category.dataOr(this.category),
4348
commentTemplate: commentTemplate.dataOr(this.commentTemplate),
4449
comments: comments.dataOr(this.comments),
4550
isFavorite: isFavorite.dataOr(this.isFavorite),

0 commit comments

Comments
 (0)