From 4d04991866f0d47426bf65e7ddf3d5ad06cec20f Mon Sep 17 00:00:00 2001 From: Zied Dahmani Date: Mon, 9 Sep 2024 23:06:48 +0100 Subject: [PATCH 1/2] refactor: merge proposal details UI with business logic --- lib/core/di/di_setup.dart | 1 + lib/core/di/usecases_module.dart | 2 + ...art => base_proposal_model_extension.dart} | 7 +- .../proposal_details_model_extension.dart | 64 ++ .../network/models/base_proposal_model.dart | 44 ++ .../models/proposal_details_model.dart | 79 +-- .../models/proposal_details_model.g.dart | 54 +- lib/core/network/models/proposal_model.dart | 38 +- lib/core/network/models/proposal_model.g.dart | 6 +- .../repository/proposal_repository.dart | 18 +- .../proposals/components/proposal_header.dart | 1 + .../components/proposal_detail_view.dart | 11 - .../components/proposal_details_view.dart | 592 +++++++++--------- .../details/components/proposal_voters.dart | 13 +- .../details/interactor/page_command.dart | 6 - .../interactor/proposal_detail_bloc.dart | 14 +- .../proposal_detail_bloc.freezed.dart | 366 +---------- .../interactor/proposal_detail_event.dart | 1 - .../interactor/proposal_detail_state.dart | 3 +- .../details/proposal_details_page.dart | 22 +- .../hypha_proposals_action_card.dart | 7 +- 21 files changed, 541 insertions(+), 808 deletions(-) rename lib/core/extension/{proposal_model_extensions.dart => base_proposal_model_extension.dart} (84%) create mode 100644 lib/core/extension/proposal_details_model_extension.dart create mode 100644 lib/core/network/models/base_proposal_model.dart delete mode 100644 lib/ui/proposals/details/components/proposal_detail_view.dart delete mode 100644 lib/ui/proposals/details/interactor/page_command.dart diff --git a/lib/core/di/di_setup.dart b/lib/core/di/di_setup.dart index 45140a8d..5b16b532 100644 --- a/lib/core/di/di_setup.dart +++ b/lib/core/di/di_setup.dart @@ -72,6 +72,7 @@ import 'package:hypha_wallet/ui/profile/usecases/remove_avatar_use_case.dart'; import 'package:hypha_wallet/ui/profile/usecases/set_bio_use_case.dart'; import 'package:hypha_wallet/ui/profile/usecases/set_image_use_case.dart'; import 'package:hypha_wallet/ui/profile/usecases/set_name_use_case.dart'; +import 'package:hypha_wallet/ui/proposals/details/usecases/get_proposal_details_use_case.dart'; import 'package:hypha_wallet/ui/proposals/list/interactor/proposals_bloc.dart'; import 'package:hypha_wallet/ui/proposals/list/usecases/get_proposals_use_case.dart'; import 'package:hypha_wallet/ui/search_user/interactor/search_user_bloc.dart'; diff --git a/lib/core/di/usecases_module.dart b/lib/core/di/usecases_module.dart index aec6bff8..74faf6ea 100644 --- a/lib/core/di/usecases_module.dart +++ b/lib/core/di/usecases_module.dart @@ -84,4 +84,6 @@ void _registerUseCasesModule() { _registerFactory(() => GetDaoNameUseCase(_getIt())); _registerFactory(() => GetProposalsUseCase(_getIt(), _getIt())); + + _registerFactory(() => GetProposalDetailsUseCase(_getIt(), _getIt())); } \ No newline at end of file diff --git a/lib/core/extension/proposal_model_extensions.dart b/lib/core/extension/base_proposal_model_extension.dart similarity index 84% rename from lib/core/extension/proposal_model_extensions.dart rename to lib/core/extension/base_proposal_model_extension.dart index 5a8825a4..fe8d5b64 100644 --- a/lib/core/extension/proposal_model_extensions.dart +++ b/lib/core/extension/base_proposal_model_extension.dart @@ -1,6 +1,6 @@ -import 'package:hypha_wallet/core/network/models/proposal_model.dart'; +import 'package:hypha_wallet/core/network/models/base_proposal_model.dart'; -extension ProposalModelTimeFormatting on ProposalModel { +extension BaseProposalModelExtension on BaseProposalModel { String formatExpiration() { if (expiration == null) return 'Expired'; @@ -32,6 +32,5 @@ extension ProposalModelTimeFormatting on ProposalModel { bool isExpired() => expiration!.toLocal().isBefore(DateTime.now()); // TODO(saif): Replace hardcoded values (.2 and .8) with dynamic values fetched from the server. // These thresholds are relative to each DAO and should be retrieved from the DAO settings. - bool isPassing()=>quorumToPercent()>=.2 && unityToPercent()>=.8; + bool isPassing() => quorumToPercent() >= .2 && unityToPercent() >= .8; } - diff --git a/lib/core/extension/proposal_details_model_extension.dart b/lib/core/extension/proposal_details_model_extension.dart new file mode 100644 index 00000000..4e2b8329 --- /dev/null +++ b/lib/core/extension/proposal_details_model_extension.dart @@ -0,0 +1,64 @@ +import 'package:hypha_wallet/core/network/models/proposal_details_model.dart'; +import 'package:intl/intl.dart'; + +extension ProposalDetailsModelExtension on ProposalDetailsModel { + double tokenMixToPercent() => tokenMixPercentage == null ? 0 : tokenMixPercentage! * .01; + + String formatCycleStartDate() => cycleStartDate != null ? DateFormat('EEEE, MMMM yyyy').format(cycleStartDate!) : ''; + + String cycleEndDate() => DateFormat('EEEE, MMMM yyyy').format(cycleStartDate!.add(Duration(days: cycleCount! * 7))); + + String? tokenTitle(int index) { + String input; + + switch (index) { + case 0: + input = cashAmount ?? cashAmountPerPeriod!; + break; + case 1: + input = voiceAmount ?? voiceAmountPerPeriod!; + break; + case 2: + input = utilityAmount ?? utilityAmountPerPeriod!; + break; + default: + return null; + } + + final RegExp regExp = RegExp(r'\d+\s+(.*)'); + final match = regExp.firstMatch(input); + + if (match != null) { + String result = match.group(1)!; + + if (result.isNotEmpty && index != 0) { + result = result[0].toLowerCase() + result.substring(1); + } + return result; + } + return null; + } + + String? tokenValue(int index) { + String input; + + switch (index) { + case 0: + input = cashAmount ?? cashAmountPerPeriod!; + break; + case 1: + input = voiceAmount ?? voiceAmountPerPeriod!; + break; + case 2: + input = utilityAmount ?? utilityAmountPerPeriod!; + break; + default: + return null; + } + + final RegExp regExp = RegExp(r'(\S+)\s'); + final match = regExp.firstMatch(input); + + return match?.group(1); + } +} diff --git a/lib/core/network/models/base_proposal_model.dart b/lib/core/network/models/base_proposal_model.dart new file mode 100644 index 00000000..cbabedd4 --- /dev/null +++ b/lib/core/network/models/base_proposal_model.dart @@ -0,0 +1,44 @@ +import 'package:hypha_wallet/core/network/models/vote_model.dart'; +import 'package:json_annotation/json_annotation.dart'; + +@JsonSerializable() +abstract class BaseProposalModel { + @JsonKey(name: 'docId') + final String id; + + @JsonKey(name: 'dao') + final String? daoName; + + @JsonKey(name: 'details_timeShareX100_i') + final int? commitment; + + @JsonKey(name: 'details_title_s') + final String? title; + + @JsonKey(name: 'details_ballotAlignment_i') + final int? unity; + + @JsonKey(name: 'details_ballotQuorum_i') + final int? quorum; + + @JsonKey(name: 'ballot_expiration_t') + final DateTime? expiration; + + @JsonKey(name: 'creator') + final String creator; + + @JsonKey(name: 'vote') + final List? votes; + + BaseProposalModel({ + required this.id, + this.daoName, + this.commitment, + this.title, + this.unity, + this.quorum, + this.expiration, + required this.creator, + this.votes, + }); +} diff --git a/lib/core/network/models/proposal_details_model.dart b/lib/core/network/models/proposal_details_model.dart index 2a8e5e5b..ce14b160 100644 --- a/lib/core/network/models/proposal_details_model.dart +++ b/lib/core/network/models/proposal_details_model.dart @@ -1,16 +1,11 @@ +import 'package:hypha_wallet/core/network/models/base_proposal_model.dart'; import 'package:hypha_wallet/core/network/models/vote_model.dart'; import 'package:json_annotation/json_annotation.dart'; part 'proposal_details_model.g.dart'; @JsonSerializable() -class ProposalDetailsModel { - @JsonKey(name: 'docId') - final String id; - - @JsonKey(name: 'creator') - final String creator; - +class ProposalDetailsModel extends BaseProposalModel { @JsonKey(name: '__typename') final String type; @@ -44,55 +39,31 @@ class ProposalDetailsModel { @JsonKey(name: 'details_rewardSalaryPerPeriod_a') final String? cashAmountPerPeriod; - @JsonKey(name: 'ballot_expiration_t') - final DateTime? expiration; - - @JsonKey(name: 'details_timeShareX100_i') - final int? commitment; - - final int? unity; - @JsonKey(name: 'details_ballotQuorum_i') - final int? quorum; - @JsonKey(name: 'details_title_s') - final String? title; - - @JsonKey(name: 'dao') - final String? daoName; @JsonKey(name: 'details_description_s') final String? description; - @JsonKey(name: 'pass') - final int? votedYesCount; - @JsonKey(name: 'fail') - final int? votedNoCount; - - @JsonKey(name: 'vote') - final List? voters; - - ProposalDetailsModel( - this.creator, - this.type, - this.creationDate, - this.utilityAmountPerPeriod, - this.voiceAmountPerPeriod, - this.cashAmountPerPeriod, - this.unity, - this.quorum, - this.voters, - this.daoName, - this.votedYesCount, - this.votedNoCount, { - required this.id, - this.title, - this.commitment, + ProposalDetailsModel({ + required super.id, + required super.creator, + required this.type, + required this.creationDate, + super.daoName, + super.commitment, + super.title, + super.unity, + super.quorum, + super.expiration, + super.votes, this.tokenMixPercentage, this.cycleCount, - this.cashAmount, this.cycleStartDate, - this.voiceAmount, this.utilityAmount, - this.description, - this.expiration, + this.voiceAmount, + this.cashAmount, + this.utilityAmountPerPeriod, + this.voiceAmountPerPeriod, + this.cashAmountPerPeriod, + this.description }); factory ProposalDetailsModel.fromJson(Map json) { @@ -106,9 +77,15 @@ class ProposalDetailsModel { json['start']=null; } } - json['dao'] = json['dao'][0]['settings'][0]['settings_daoTitle_s']; + // TODO(Saif): check this + if(json['dao'] != null) { + json['dao'] = json['dao'][0]['settings'][0]['settings_daoTitle_s']; + } return _$ProposalDetailsModelFromJson(json); } - Map toJson() => _$ProposalDetailsModelToJson(this); + List fetchVotersByStatus(VoteStatus voteStatus) => votes + ?.where((vote) => vote.voteStatus == voteStatus) + .map((vote) => vote) + .toList() ?? []; } diff --git a/lib/core/network/models/proposal_details_model.g.dart b/lib/core/network/models/proposal_details_model.g.dart index f0314723..1121ce3f 100644 --- a/lib/core/network/models/proposal_details_model.g.dart +++ b/lib/core/network/models/proposal_details_model.g.dart @@ -9,42 +9,47 @@ part of 'proposal_details_model.dart'; ProposalDetailsModel _$ProposalDetailsModelFromJson( Map json) => ProposalDetailsModel( - json['creator'] as String, - json['__typename'] as String, - DateTime.parse(json['createdDate'] as String), - json['details_pegSalaryPerPeriod_a'] as String?, - json['details_voiceSalaryPerPeriod_a'] as String?, - json['details_rewardSalaryPerPeriod_a'] as String?, - (json['unity'] as num?)?.toInt(), - (json['details_ballotQuorum_i'] as num?)?.toInt(), - (json['vote'] as List?) - ?.map((e) => VoteModel.fromJson(e as Map)) - .toList(), - json['dao'] as String?, - (json['pass'] as num?)?.toInt(), - (json['fail'] as num?)?.toInt(), id: json['docId'] as String, - title: json['details_title_s'] as String?, + creator: json['creator'] as String, + type: json['__typename'] as String, + creationDate: DateTime.parse(json['createdDate'] as String), + daoName: json['dao'] as String?, commitment: (json['details_timeShareX100_i'] as num?)?.toInt(), + title: json['details_title_s'] as String?, + unity: (json['details_ballotAlignment_i'] as num?)?.toInt(), + quorum: (json['details_ballotQuorum_i'] as num?)?.toInt(), + expiration: json['ballot_expiration_t'] == null + ? null + : DateTime.parse(json['ballot_expiration_t'] as String), + votes: (json['vote'] as List?) + ?.map((e) => VoteModel.fromJson(e as Map)) + .toList(), tokenMixPercentage: (json['details_deferredPercX100_i'] as num?)?.toInt(), cycleCount: (json['details_periodCount_i'] as num?)?.toInt(), - cashAmount: json['details_rewardAmount_a'] as String?, cycleStartDate: json['start'] == null ? null : DateTime.parse(json['start'] as String), - voiceAmount: json['details_voiceAmount_a'] as String?, utilityAmount: json['details_pegAmount_a'] as String?, + voiceAmount: json['details_voiceAmount_a'] as String?, + cashAmount: json['details_rewardAmount_a'] as String?, + utilityAmountPerPeriod: json['details_pegSalaryPerPeriod_a'] as String?, + voiceAmountPerPeriod: json['details_voiceSalaryPerPeriod_a'] as String?, + cashAmountPerPeriod: json['details_rewardSalaryPerPeriod_a'] as String?, description: json['details_description_s'] as String?, - expiration: json['ballot_expiration_t'] == null - ? null - : DateTime.parse(json['ballot_expiration_t'] as String), ); Map _$ProposalDetailsModelToJson( ProposalDetailsModel instance) => { 'docId': instance.id, + 'dao': instance.daoName, + 'details_timeShareX100_i': instance.commitment, + 'details_title_s': instance.title, + 'details_ballotAlignment_i': instance.unity, + 'details_ballotQuorum_i': instance.quorum, + 'ballot_expiration_t': instance.expiration?.toIso8601String(), 'creator': instance.creator, + 'vote': instance.votes, '__typename': instance.type, 'createdDate': instance.creationDate.toIso8601String(), 'details_deferredPercX100_i': instance.tokenMixPercentage, @@ -56,14 +61,5 @@ Map _$ProposalDetailsModelToJson( 'details_pegSalaryPerPeriod_a': instance.utilityAmountPerPeriod, 'details_voiceSalaryPerPeriod_a': instance.voiceAmountPerPeriod, 'details_rewardSalaryPerPeriod_a': instance.cashAmountPerPeriod, - 'ballot_expiration_t': instance.expiration?.toIso8601String(), - 'details_timeShareX100_i': instance.commitment, - 'unity': instance.unity, - 'details_ballotQuorum_i': instance.quorum, - 'details_title_s': instance.title, - 'dao': instance.daoName, 'details_description_s': instance.description, - 'pass': instance.votedYesCount, - 'fail': instance.votedNoCount, - 'vote': instance.voters, }; diff --git a/lib/core/network/models/proposal_model.dart b/lib/core/network/models/proposal_model.dart index f144cbe1..20b77f51 100644 --- a/lib/core/network/models/proposal_model.dart +++ b/lib/core/network/models/proposal_model.dart @@ -1,38 +1,26 @@ +import 'package:hypha_wallet/core/network/models/base_proposal_model.dart'; import 'package:hypha_wallet/core/network/models/vote_model.dart'; import 'package:json_annotation/json_annotation.dart'; part 'proposal_model.g.dart'; @JsonSerializable() -class ProposalModel { - @JsonKey(name: 'docId') - final String id; - final String daoName; - @JsonKey(name: 'details_timeShareX100_i') - final int? commitment; - @JsonKey(name: 'details_title_s') - final String? title; - @JsonKey(name: 'details_ballotAlignment_i') - final int? unity; - @JsonKey(name: 'details_ballotQuorum_i') - final int? quorum; - @JsonKey(name: 'ballot_expiration_t') - final DateTime? expiration; - final String creator; - @JsonKey(name: 'vote') - final List? votes; - - ProposalModel({required this.id, required this.daoName, this.commitment, this.title, this.unity, this.quorum, this.expiration, required this.creator, this.votes}); - +class ProposalModel extends BaseProposalModel{ + ProposalModel({ + required super.id, + required super.creator, + super.daoName, + super.commitment, + super.title, + super.unity, + super.quorum, + super.expiration, + super.votes, + }); factory ProposalModel.fromJson(Map json) { if (json.containsKey('original')) { json['details_title_s'] = json['original'][0]['details_title_s']; } return _$ProposalModelFromJson(json); } - - List fetchVotersByStatus(VoteStatus voteStatus) => votes - ?.where((vote) => vote.voteStatus == voteStatus) - .map((vote) => vote.voter) - .toList() ?? []; } diff --git a/lib/core/network/models/proposal_model.g.dart b/lib/core/network/models/proposal_model.g.dart index a1c1672b..9b3d0cb0 100644 --- a/lib/core/network/models/proposal_model.g.dart +++ b/lib/core/network/models/proposal_model.g.dart @@ -9,7 +9,8 @@ part of 'proposal_model.dart'; ProposalModel _$ProposalModelFromJson(Map json) => ProposalModel( id: json['docId'] as String, - daoName: json['daoName'] as String, + creator: json['creator'] as String, + daoName: json['dao'] as String?, commitment: (json['details_timeShareX100_i'] as num?)?.toInt(), title: json['details_title_s'] as String?, unity: (json['details_ballotAlignment_i'] as num?)?.toInt(), @@ -17,7 +18,6 @@ ProposalModel _$ProposalModelFromJson(Map json) => expiration: json['ballot_expiration_t'] == null ? null : DateTime.parse(json['ballot_expiration_t'] as String), - creator: json['creator'] as String, votes: (json['vote'] as List?) ?.map((e) => VoteModel.fromJson(e as Map)) .toList(), @@ -26,7 +26,7 @@ ProposalModel _$ProposalModelFromJson(Map json) => Map _$ProposalModelToJson(ProposalModel instance) => { 'docId': instance.id, - 'daoName': instance.daoName, + 'dao': instance.daoName, 'details_timeShareX100_i': instance.commitment, 'details_title_s': instance.title, 'details_ballotAlignment_i': instance.unity, diff --git a/lib/core/network/repository/proposal_repository.dart b/lib/core/network/repository/proposal_repository.dart index 8ab5e985..0aa47599 100644 --- a/lib/core/network/repository/proposal_repository.dart +++ b/lib/core/network/repository/proposal_repository.dart @@ -1,5 +1,5 @@ import 'package:hypha_wallet/core/error_handler/model/hypha_error.dart'; -import 'package:hypha_wallet/core/extension/proposal_model_extensions.dart'; +import 'package:hypha_wallet/core/extension/base_proposal_model_extension.dart'; import 'package:hypha_wallet/core/logging/log_helper.dart'; import 'package:hypha_wallet/core/network/api/services/proposal_service.dart'; import 'package:hypha_wallet/core/network/models/dao_data_model.dart'; @@ -58,20 +58,20 @@ class ProposalRepository { final String daoName = dao['details_daoName_n']; final List proposals = dao['proposal'] as List; return proposals.map((dynamic proposal) { - return ProposalModel.fromJson({...{'daoName': daoName}, ...proposal}); + return ProposalModel.fromJson({...{'dao': daoName}, ...proposal}); }); }).toList(); } void sortProposals(List proposals) { proposals.sort((a, b) { - final daoNameComparison = a.daoName.compareTo(b.daoName); + final int daoNameComparison = (a.daoName ?? '').compareTo(b.daoName ?? ''); if (daoNameComparison != 0) { return daoNameComparison; } - final isAExpired = a.expiration != null && a.isExpired(); - final isBExpired = b.expiration != null && b.isExpired(); + final bool isAExpired = a.expiration != null && a.isExpired(); + final bool isBExpired = b.expiration != null && b.isExpired(); if (isAExpired && !isBExpired) { return 1; @@ -97,13 +97,13 @@ class ProposalRepository { final Map response = result.valueOrCrash; final ProposalDetailsModel proposalDetails = ProposalDetailsModel.fromJson(response['data']['getDocument']); - if (proposalDetails.voters != null) { - for (int i = 0; i < proposalDetails.voters!.length; i++) { + if (proposalDetails.votes != null) { + for (int i = 0; i < proposalDetails.votes!.length; i++) { final Result voterData = await _profileService - .getProfile(proposalDetails.voters![i].voter); + .getProfile(proposalDetails.votes![i].voter); if (voterData.isValue) { - proposalDetails.voters![i].voterImageUrl = + proposalDetails.votes![i].voterImageUrl = voterData.asValue!.value.avatarUrl; } } diff --git a/lib/ui/proposals/components/proposal_header.dart b/lib/ui/proposals/components/proposal_header.dart index 9656cdf2..0e00634a 100644 --- a/lib/ui/proposals/components/proposal_header.dart +++ b/lib/ui/proposals/components/proposal_header.dart @@ -26,6 +26,7 @@ class ProposalHeader extends StatelessWidget { ), ), const SizedBox(width: 10), + // TODO(Zied-Saif): figure this out Text( 'Marketing Circle', style: context.hyphaTextTheme.ralMediumSmallNote, diff --git a/lib/ui/proposals/details/components/proposal_detail_view.dart b/lib/ui/proposals/details/components/proposal_detail_view.dart deleted file mode 100644 index 7282940f..00000000 --- a/lib/ui/proposals/details/components/proposal_detail_view.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/material.dart'; -class ProposalDetailView extends StatelessWidget { - const ProposalDetailView({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - ); - } -} diff --git a/lib/ui/proposals/details/components/proposal_details_view.dart b/lib/ui/proposals/details/components/proposal_details_view.dart index 67003b67..d9cbb310 100644 --- a/lib/ui/proposals/details/components/proposal_details_view.dart +++ b/lib/ui/proposals/details/components/proposal_details_view.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get/get_utils/src/extensions/context_extensions.dart'; -import 'package:hypha_wallet/core/extension/proposal_model_extensions.dart'; -import 'package:hypha_wallet/core/network/models/proposal_model.dart'; +import 'package:hypha_wallet/core/extension/base_proposal_model_extension.dart'; +import 'package:hypha_wallet/core/extension/proposal_details_model_extension.dart'; +import 'package:hypha_wallet/core/network/models/proposal_details_model.dart'; import 'package:hypha_wallet/core/network/models/vote_model.dart'; import 'package:hypha_wallet/design/avatar_image/hypha_avatar_image.dart'; import 'package:hypha_wallet/design/background/hypha_page_background.dart'; @@ -10,46 +12,37 @@ import 'package:hypha_wallet/design/buttons/hypha_app_button.dart'; import 'package:hypha_wallet/design/dividers/hypha_divider.dart'; import 'package:hypha_wallet/design/hypha_colors.dart'; import 'package:hypha_wallet/design/themes/extensions/theme_extension_provider.dart'; -import 'package:hypha_wallet/ui/proposals/components/proposal_creator.dart'; import 'package:hypha_wallet/ui/proposals/components/proposal_button.dart'; +import 'package:hypha_wallet/ui/proposals/components/proposal_creator.dart'; import 'package:hypha_wallet/ui/proposals/components/proposal_expiration_timer.dart'; import 'package:hypha_wallet/ui/proposals/components/proposal_header.dart'; import 'package:hypha_wallet/ui/proposals/components/proposal_percentage_indicator.dart'; import 'package:hypha_wallet/ui/proposals/details/components/proposal_voters.dart'; +import 'package:hypha_wallet/ui/proposals/details/interactor/proposal_detail_bloc.dart'; +import 'package:hypha_wallet/ui/shared/hypha_body_widget.dart'; class ProposalDetailsView extends StatefulWidget { - final ProposalModel proposalModel; - - const ProposalDetailsView(this.proposalModel, {super.key}); + const ProposalDetailsView({super.key}); @override State createState() => _ProposalDetailsViewState(); } class _ProposalDetailsViewState extends State { - final ValueNotifier _isShown = ValueNotifier(true); - final ValueNotifier _isOverflowing = ValueNotifier(false); - final ValueNotifier _isExpanded = ValueNotifier(false); - late List passVoters = widget.proposalModel.fetchVotersByStatus(VoteStatus.pass); - late List failVoters = widget.proposalModel.fetchVotersByStatus(VoteStatus.fail); - - @override - void initState() { - super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - _checkIfTextIsOverflowing(); - }); - } + final ValueNotifier _isShownNotifier = ValueNotifier(true); + final ValueNotifier _isOverflowingNotifier = ValueNotifier(false); + final ValueNotifier _isExpandedNotifier = ValueNotifier(false); + final ValueNotifier _detailsNotifier = ValueNotifier(null); void _checkIfTextIsOverflowing() { final TextPainter textPainter = TextPainter( - text: TextSpan(text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel lacus eget enim tincidunt viverra eget sit amet ex. Phasellus bibendum congue porta. Aenean pellentesque ut dolor pharetra volutpat. Proin ut eleifend dolor, sed faucibus ipsum. Vestibulum sollicitudin nibh ut ligula sollicitudin, vitae convallis arcu egestas. Vivamus sollicitudin leo non elit blandit rutrum. Morbi auctor neque ipsum, et varius dolor finibus eget. Curabitur pulvinar arcu sit amet porta posuere. Cras mollis massa id neque tempus, a cursus leo interdum. Etiam ut dolor vel ex ullamcorper tempor vel vel tellus. Praesent hendrerit lobortis interdum. Fusce posuere in neque iaculis ullamcorper. Vivamus vestibulum posuere purus, quis sagittis ex interdum vel. Donec convallis augue et nisl sodales, et luctus massa ultrices.', style: context.hyphaTextTheme.ralMediumBody), + text: TextSpan(text: _detailsNotifier.value), maxLines: 3, textDirection: TextDirection.ltr, )..layout(maxWidth: context.size!.width); if (textPainter.didExceedMaxLines) { - _isOverflowing.value = true; + _isOverflowingNotifier.value = true; } } @@ -63,298 +56,321 @@ class _ProposalDetailsViewState extends State { scrolledUnderElevation: 0, title: const Text('Proposal Details'), ), - body: Padding( - padding: const EdgeInsets.symmetric(horizontal: 30), - child: ListView( - children: [ - const SizedBox(height: 20), - /// Header - ProposalHeader( - widget.proposalModel.daoName, - 'https://etudestech.com/wp-content/uploads/2023/05/midjourney-scaled.jpeg', - ), - const Padding( - padding: EdgeInsets.only(top: 10, bottom: 20), - child: HyphaDivider(), - ), - /// Main Section - Wrap( - children: List.generate( - widget.proposalModel.commitment != null ? 3 : 2, - (index) => Padding( - padding: const EdgeInsets.only(right: 10), - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), - decoration: BoxDecoration( - border: Border.all( - color: context.isDarkMode - ? HyphaColors.white - : HyphaColors.lightBlack, - ), - borderRadius: BorderRadius.circular(20), - ), - child: Text( - index == 0 - ? 'Role Assignment' - : index == 1 + body: BlocBuilder( + builder: (context, state) { + return HyphaBodyWidget(pageState: state.pageState, success: (context) { + final ProposalDetailsModel _proposalDetailsModel = state.proposalDetailsModel!; + final List passVoters = _proposalDetailsModel.fetchVotersByStatus(VoteStatus.pass); + final List failVoters = _proposalDetailsModel.fetchVotersByStatus(VoteStatus.fail); + _detailsNotifier.value = _proposalDetailsModel.description; + WidgetsBinding.instance.addPostFrameCallback((_) { + _checkIfTextIsOverflowing(); + }); + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 30), + child: ListView( + children: [ + const SizedBox(height: 20), + /// Header + // TODO(Saif): display DAO image + ProposalHeader( + _proposalDetailsModel.daoName ?? '', + 'https://etudestech.com/wp-content/uploads/2023/05/midjourney-scaled.jpeg', + ), + const Padding( + padding: EdgeInsets.only(top: 10, bottom: 20), + child: HyphaDivider(), + ), + /// Main Section + Wrap( + children: List.generate( + _proposalDetailsModel.commitment != null ? 3 : 2, + (index) => Padding( + padding: const EdgeInsets.only(right: 10), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + border: Border.all( + color: context.isDarkMode + ? HyphaColors.white + : HyphaColors.lightBlack, + ), + borderRadius: BorderRadius.circular(20), + ), + // TODO(Zied-Saif): figure these out (B6 and Role) + child: Text( + index == 0 + ? 'Role ${_proposalDetailsModel.type}' + : index == 1 ? 'B6' - : '${widget.proposalModel.commitment}%', - style: context.hyphaTextTheme.ralBold, + : '${_proposalDetailsModel.commitment}%', + style: context.hyphaTextTheme.ralBold, + ), + ), ), ), ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 20), - child: Text( - widget.proposalModel.title ?? 'No title set for this proposal.', - style: context.hyphaTextTheme.mediumTitles, - ), - ), - ProposalCreator( - widget.proposalModel.creator, - 'https://etudestech.com/wp-content/uploads/2023/05/midjourney-scaled.jpeg', - ), - ...List.generate( - 2, - (index) => Padding( - padding: const EdgeInsets.only(top: 20), - child: ProposalPercentageIndicator( - index == 0 ? 'Commitment' : 'Token Mix Percentage', - index == 0 ? widget.proposalModel.commitmentToPercent() : .4, - HyphaColors.lightBlue + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Text( + _proposalDetailsModel.title ?? 'No title', + style: context.hyphaTextTheme.mediumTitles, + ), ), - ), - ), - const SizedBox(height: 20), - Text( - 'Duration', - style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Text( - '12 Cycles', - style: context.hyphaTextTheme.reducedTitles, - ), - ), - ...List.generate( - 2, - (index) => Text( - 'Starting on Monday', - style: context.hyphaTextTheme.ralMediumBody.copyWith(color: HyphaColors.midGrey), - ), - ), - const Padding( - padding: EdgeInsets.symmetric(vertical: 20), - child: HyphaDivider(), - ), - /// Rewards Section - ValueListenableBuilder( - valueListenable: _isShown, - builder: (context, isShown, child) { - return isShown ? Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Reward for 1 cycle', - style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey), + // TODO(Saif): display creator image + ProposalCreator( + _proposalDetailsModel.creator, + 'https://etudestech.com/wp-content/uploads/2023/05/midjourney-scaled.jpeg', + ), + ...List.generate( + 2, + (index) => Padding( + padding: const EdgeInsets.only(top: 20), + child: ProposalPercentageIndicator( + index == 0 ? 'Commitment' : 'Token Mix Percentage', + index == 0 ? _proposalDetailsModel.commitmentToPercent() : _proposalDetailsModel.tokenMixToPercent(), + HyphaColors.lightBlue + ), + ), + ), + if (!(_proposalDetailsModel.cycleCount == null && _proposalDetailsModel.cycleStartDate == null)) ...[ + const SizedBox(height: 20), + Text( + 'Duration', + style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + '${_proposalDetailsModel.cycleCount} Cycles', + style: context.hyphaTextTheme.reducedTitles, ), - ...List.generate( - 3, - (index) => Padding( - padding: const EdgeInsets.only(top: 10), - child: Row( - children: [ - const HyphaAvatarImage( - imageRadius: 24, - imageFromUrl: - 'https://etudestech.com/wp-content/uploads/2023/05/midjourney-scaled.jpeg', - ), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + ), + ...List.generate( + 2, + (index) => Text( + index == 0 ? 'Starting on ${_proposalDetailsModel.formatCycleStartDate()}' : + 'Ending on ${_proposalDetailsModel.cycleEndDate()}', + style: context.hyphaTextTheme.ralMediumBody.copyWith(color: HyphaColors.midGrey), + ), + ), + ], + const Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: HyphaDivider(), + ), + /// Rewards Section + // TODO(Zied): implement the logic + if (!(_proposalDetailsModel.utilityAmount == null && _proposalDetailsModel.utilityAmountPerPeriod == null)) ... [ + ValueListenableBuilder( + valueListenable: _isShownNotifier, + builder: (context, isShown, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Reward for 1 cycle', + style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey), + ), + ...List.generate( + 3, + (index) => Padding( + padding: const EdgeInsets.only(top: 10), + child: Row( children: [ - Text( - 'Hypha', - style: context.hyphaTextTheme.reducedTitles, - overflow: TextOverflow.ellipsis, + const HyphaAvatarImage( + imageRadius: 24, + imageFromUrl: 'https://etudestech.com/wp-content/uploads/2023/05/midjourney-scaled.jpeg', ), - Text( - 'Utility Token', - style: context.hyphaTextTheme.ralMediumBody.copyWith(color: HyphaColors.midGrey), - overflow: TextOverflow.ellipsis, + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + _proposalDetailsModel.tokenTitle(index) ?? '', + style: context.hyphaTextTheme.reducedTitles, + overflow: TextOverflow.ellipsis, + ), + Text( + index == 0 ? 'Utility Token' : index == 1 ? 'Voice Token' : 'Cash Token', + style: context.hyphaTextTheme.ralMediumBody.copyWith(color: HyphaColors.midGrey), + overflow: TextOverflow.ellipsis, + ), + ], + ), ), + const SizedBox(width: 10), + Text( + _proposalDetailsModel.tokenValue(index) ?? '', + style: context.hyphaTextTheme.bigTitles.copyWith(fontWeight: FontWeight.normal), + ) ], ), - ), - const SizedBox(width: 10), - Text( - '3,200.00', - style: context.hyphaTextTheme.bigTitles.copyWith(fontWeight: FontWeight.normal), - ), - ], - ), - )), - const SizedBox(height: 10) - ], - ) : const SizedBox.shrink(); - }, - ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - 'Show rewards for 1 cycle', - style: context.hyphaTextTheme.ralMediumBody.copyWith(color: HyphaColors.midGrey), - overflow: TextOverflow.ellipsis, + )), + const SizedBox(height: 10) + ], + ); + }, ), - ), - const SizedBox(width: 10), - ValueListenableBuilder( - valueListenable: _isShown, - builder: (BuildContext context, bool value, Widget? child) { - return Switch( - value: value, - onChanged: (newValue) { - _isShown.value = newValue; - }, - ); - }, - ), - ], - ), - const Padding( - padding: EdgeInsets.symmetric(vertical: 20), - child: HyphaDivider(), - ), - /// Details Section - Text( - 'Proposal Details', - style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey), - ), - ValueListenableBuilder( - valueListenable: _isExpanded, - builder: (context, isExpanded, child) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.only(top: 10), - child: Text( - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vel lacus eget enim tincidunt viverra eget sit amet ex. Phasellus bibendum congue porta. Aenean pellentesque ut dolor pharetra volutpat. Proin ut eleifend dolor, sed faucibus ipsum. Vestibulum sollicitudin nibh ut ligula sollicitudin, vitae convallis arcu egestas. Vivamus sollicitudin leo non elit blandit rutrum. Morbi auctor neque ipsum, et varius dolor finibus eget. Curabitur pulvinar arcu sit amet porta posuere. Cras mollis massa id neque tempus, a cursus leo interdum. Etiam ut dolor vel ex ullamcorper tempor vel vel tellus. Praesent hendrerit lobortis interdum. Fusce posuere in neque iaculis ullamcorper. Vivamus vestibulum posuere purus, quis sagittis ex interdum vel. Donec convallis augue et nisl sodales, et luctus massa ultrices.', - style: context.hyphaTextTheme.ralMediumBody, - maxLines: isExpanded ? null : 3, - overflow: isExpanded ? TextOverflow.visible : TextOverflow.ellipsis, + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Text( + 'Show rewards for 1 cycle', + style: context.hyphaTextTheme.ralMediumBody.copyWith(color: HyphaColors.midGrey), + overflow: TextOverflow.ellipsis, + ), ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 20), - child: Row( - children: [ - const Expanded(child: HyphaDivider()), - ValueListenableBuilder( - valueListenable: _isOverflowing, - builder: (context, isOverflowing, child) { - return isOverflowing - ? ProposalButton( - isExpanded ? 'Collapse' : 'Expand', - isExpanded - ? Icons.keyboard_arrow_up_outlined - : Icons.keyboard_arrow_down_outlined, - () => _isExpanded.value = !isExpanded, - ) - : const SizedBox.shrink(); + const SizedBox(width: 10), + ValueListenableBuilder( + valueListenable: _isShownNotifier, + builder: (BuildContext context, bool value, Widget? child) { + return Switch( + value: value, + onChanged: (newValue) { + _isShownNotifier.value = newValue; }, + ); + }, + ), + ], + ), + const Padding( + padding: EdgeInsets.symmetric(vertical: 20), + child: HyphaDivider(), + ), + ], + /// Details Section + if (_proposalDetailsModel.description != null) ... [ + Text( + 'Proposal Details', + style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey), + ), + ValueListenableBuilder( + valueListenable: _isExpandedNotifier, + builder: (context, isExpanded, child) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10), + child: Text( + _proposalDetailsModel.description ?? '', + style: context.hyphaTextTheme.ralMediumBody, + maxLines: isExpanded ? null : 3, + overflow: isExpanded ? TextOverflow.visible : TextOverflow.ellipsis, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Row( + children: [ + const Expanded(child: HyphaDivider()), + ValueListenableBuilder( + valueListenable: _isOverflowingNotifier, + builder: (context, isOverflowing, child) { + return isOverflowing + ? ProposalButton( + isExpanded ? 'Collapse' : 'Expand', + isExpanded + ? Icons.keyboard_arrow_up_outlined + : Icons.keyboard_arrow_down_outlined, + () => _isExpandedNotifier.value = !isExpanded, + ) + : const SizedBox.shrink(); + }, + ), + ], + ), ), ], - ), + ); + }, + ), + ], + /// Voting Scores Section + Text( + 'Voting Scores', + style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey), + ), + if(passVoters.isNotEmpty) ... [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + '${passVoters.length} members voted Yes', + style: context.hyphaTextTheme.reducedTitles, ), - ], - ); - }, - ), - /// Voting Scores Section - Text( - 'Voting Scores', - style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey), - ), - if(passVoters.isNotEmpty) ... [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Text( - '${passVoters.length} members voted Yes', - style: context.hyphaTextTheme.reducedTitles, + ), + ProposalVoters(passVoters) + ], + if(failVoters.isNotEmpty) ... [ + Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: Text( + '${failVoters.length} members voted No', + style: context.hyphaTextTheme.reducedTitles, + ), + ), + ProposalVoters(failVoters) + ], + const SizedBox(height: 20), + ...List.generate( + 2, + (index) => Padding( + padding: const EdgeInsets.only(bottom: 20), + child: ProposalPercentageIndicator( + index == 0 ? 'Unity' : 'Quorum', + index == 0 ? _proposalDetailsModel.unityToPercent() : _proposalDetailsModel.quorumToPercent(), + _proposalDetailsModel.isPassing() ? HyphaColors.success : HyphaColors.error + ), + ), ), - ), - ProposalVoters(passVoters) - ], - if(failVoters.isNotEmpty) ... [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: Text( - '${failVoters.length} members voted No', - style: context.hyphaTextTheme.reducedTitles, + const HyphaDivider(), + /// Expiration Timer + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: ProposalExpirationTimer( + _proposalDetailsModel.formatExpiration(), + ), ), - ), - ProposalVoters(failVoters) - ], - const SizedBox(height: 20), - ...List.generate( - 2, - (index) => Padding( - padding: const EdgeInsets.only(bottom: 20), - child: ProposalPercentageIndicator( - index == 0 ? 'Unity' : 'Quorum', - index == 0 ? widget.proposalModel.unityToPercent() : widget.proposalModel.quorumToPercent(), - widget.proposalModel.isPassing()?HyphaColors.success:HyphaColors.error + const HyphaDivider(), + /// Vote Section + Padding( + padding: const EdgeInsets.symmetric(vertical: 20), + child: Text( + 'Cast your Vote', + style: context.hyphaTextTheme.smallTitles, + ), ), - ), - ), - const HyphaDivider(), - /// Expiration Timer - Padding( - padding: const EdgeInsets.symmetric(vertical: 20), - child: ProposalExpirationTimer( - widget.proposalModel.formatExpiration(), - ), - ), - const HyphaDivider(), - /// Vote Section - Padding( - padding: const EdgeInsets.symmetric(vertical: 20), - child: Text( - 'Cast your Vote', - style: context.hyphaTextTheme.smallTitles, - ), - ), - ...List.generate( - 3, - (index) => Padding( - padding: const EdgeInsets.symmetric(vertical: 10), - child: HyphaAppButton( - title: index == 0 - ? 'Yes' - : index == 1 + ...List.generate( + 3, + (index) => Padding( + padding: const EdgeInsets.symmetric(vertical: 10), + child: HyphaAppButton( + title: index == 0 + ? 'Yes' + : index == 1 ? 'Abstain' : 'No', - onPressed: () async {}, - buttonType: ButtonType.danger, - buttonColor: index == 0 - ? HyphaColors.success - : index == 1 - ? HyphaColors.lightBlack - : HyphaColors.error, + onPressed: () async {}, + buttonType: ButtonType.danger, + buttonColor: index == 0 + ? HyphaColors.success + : index == 1 + ? HyphaColors.lightBlack + : HyphaColors.error, + ), + ), ), - ), + const SizedBox(height: 20), + ], ), - const SizedBox(height: 20), - ], - ), - ), + ); + }); + }, + ), ), ); } diff --git a/lib/ui/proposals/details/components/proposal_voters.dart b/lib/ui/proposals/details/components/proposal_voters.dart index edbdab2b..19e297d7 100644 --- a/lib/ui/proposals/details/components/proposal_voters.dart +++ b/lib/ui/proposals/details/components/proposal_voters.dart @@ -1,13 +1,14 @@ import 'package:flutter/material.dart'; import 'package:get/get_utils/src/extensions/context_extensions.dart'; +import 'package:hypha_wallet/core/network/models/vote_model.dart'; import 'package:hypha_wallet/design/avatar_image/hypha_avatar_image.dart'; import 'package:hypha_wallet/design/hypha_colors.dart'; import 'package:hypha_wallet/design/themes/extensions/theme_extension_provider.dart'; class ProposalVoters extends StatelessWidget { - final List voters; + final List votes; - const ProposalVoters(this.voters, {super.key}); + const ProposalVoters(this.votes, {super.key}); @override Widget build(BuildContext context) { @@ -15,7 +16,7 @@ class ProposalVoters extends StatelessWidget { height: 50, child: Stack( children: List.generate( - voters.take(9).length, + votes.take(9).length, (index) { return Positioned( left: index * 30.0, @@ -34,7 +35,7 @@ class ProposalVoters extends StatelessWidget { ), child: Center( child: Text( - '+${voters.length - 8}', + '+${votes.length - 8}', style: context.hyphaTextTheme.reducedTitles.copyWith( color: context.isDarkMode ? HyphaColors.offWhite @@ -43,9 +44,9 @@ class ProposalVoters extends StatelessWidget { ), ), ) - : const HyphaAvatarImage( + : HyphaAvatarImage( imageRadius: 24, - imageFromUrl: 'https://etudestech.com/wp-content/uploads/2023/05/midjourney-scaled.jpeg', + imageFromUrl: votes[index].voterImageUrl, ), ); }, diff --git a/lib/ui/proposals/details/interactor/page_command.dart b/lib/ui/proposals/details/interactor/page_command.dart deleted file mode 100644 index eebe1fa6..00000000 --- a/lib/ui/proposals/details/interactor/page_command.dart +++ /dev/null @@ -1,6 +0,0 @@ -part of 'proposal_detail_bloc.dart'; - -@freezed -class PageCommand with _$PageCommand { - const factory PageCommand.navigateToProposalDetails() = _NavigateToProposalDetails; -} diff --git a/lib/ui/proposals/details/interactor/proposal_detail_bloc.dart b/lib/ui/proposals/details/interactor/proposal_detail_bloc.dart index 38c4b80b..aeafff43 100644 --- a/lib/ui/proposals/details/interactor/proposal_detail_bloc.dart +++ b/lib/ui/proposals/details/interactor/proposal_detail_bloc.dart @@ -1,17 +1,13 @@ import 'dart:async'; - import 'package:bloc/bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:hypha_wallet/core/error_handler/error_handler_manager.dart'; +import 'package:hypha_wallet/core/error_handler/model/hypha_error.dart'; import 'package:hypha_wallet/core/network/models/proposal_details_model.dart'; import 'package:hypha_wallet/ui/architecture/interactor/page_states.dart'; +import 'package:hypha_wallet/ui/architecture/result/result.dart'; import 'package:hypha_wallet/ui/proposals/details/usecases/get_proposal_details_use_case.dart'; -import '../../../../core/error_handler/error_handler_manager.dart'; -import '../../../../core/error_handler/model/hypha_error.dart'; -import '../../../../core/network/models/proposal_model.dart'; -import '../../../architecture/result/result.dart'; - -part 'page_command.dart'; part 'proposal_detail_bloc.freezed.dart'; part 'proposal_detail_event.dart'; part 'proposal_detail_state.dart'; @@ -26,9 +22,11 @@ class ProposalDetailBloc extends Bloc } Future _initial(_Initial event, Emitter emit) async { + emit(state.copyWith(pageState: PageState.loading)); + final Result result = await _getProposalDetailsUseCase.run(_proposalId); if (result.isValue) { - emit(state.copyWith(pageState: PageState.success)); + emit(state.copyWith(pageState: PageState.success, proposalDetailsModel: result.asValue!.value)); } else { await _errorHandlerManager.handlerError(result.asError!.error); emit(state.copyWith(pageState: PageState.failure)); diff --git a/lib/ui/proposals/details/interactor/proposal_detail_bloc.freezed.dart b/lib/ui/proposals/details/interactor/proposal_detail_bloc.freezed.dart index 1f92e200..713b2be4 100644 --- a/lib/ui/proposals/details/interactor/proposal_detail_bloc.freezed.dart +++ b/lib/ui/proposals/details/interactor/proposal_detail_bloc.freezed.dart @@ -14,208 +14,37 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); -/// @nodoc -mixin _$PageCommand { - @optionalTypeArgs - TResult when({ - required TResult Function() navigateToProposalDetails, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? navigateToProposalDetails, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? navigateToProposalDetails, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult map({ - required TResult Function(_NavigateToProposalDetails value) - navigateToProposalDetails, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(_NavigateToProposalDetails value)? - navigateToProposalDetails, - }) => - throw _privateConstructorUsedError; - @optionalTypeArgs - TResult maybeMap({ - TResult Function(_NavigateToProposalDetails value)? - navigateToProposalDetails, - required TResult orElse(), - }) => - throw _privateConstructorUsedError; -} - -/// @nodoc -abstract class $PageCommandCopyWith<$Res> { - factory $PageCommandCopyWith( - PageCommand value, $Res Function(PageCommand) then) = - _$PageCommandCopyWithImpl<$Res, PageCommand>; -} - -/// @nodoc -class _$PageCommandCopyWithImpl<$Res, $Val extends PageCommand> - implements $PageCommandCopyWith<$Res> { - _$PageCommandCopyWithImpl(this._value, this._then); - - // ignore: unused_field - final $Val _value; - // ignore: unused_field - final $Res Function($Val) _then; - - /// Create a copy of PageCommand - /// with the given fields replaced by the non-null parameter values. -} - -/// @nodoc -abstract class _$$NavigateToProposalDetailsImplCopyWith<$Res> { - factory _$$NavigateToProposalDetailsImplCopyWith( - _$NavigateToProposalDetailsImpl value, - $Res Function(_$NavigateToProposalDetailsImpl) then) = - __$$NavigateToProposalDetailsImplCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$NavigateToProposalDetailsImplCopyWithImpl<$Res> - extends _$PageCommandCopyWithImpl<$Res, _$NavigateToProposalDetailsImpl> - implements _$$NavigateToProposalDetailsImplCopyWith<$Res> { - __$$NavigateToProposalDetailsImplCopyWithImpl( - _$NavigateToProposalDetailsImpl _value, - $Res Function(_$NavigateToProposalDetailsImpl) _then) - : super(_value, _then); - - /// Create a copy of PageCommand - /// with the given fields replaced by the non-null parameter values. -} - -/// @nodoc - -class _$NavigateToProposalDetailsImpl implements _NavigateToProposalDetails { - const _$NavigateToProposalDetailsImpl(); - - @override - String toString() { - return 'PageCommand.navigateToProposalDetails()'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && - other is _$NavigateToProposalDetailsImpl); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() navigateToProposalDetails, - }) { - return navigateToProposalDetails(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? navigateToProposalDetails, - }) { - return navigateToProposalDetails?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? navigateToProposalDetails, - required TResult orElse(), - }) { - if (navigateToProposalDetails != null) { - return navigateToProposalDetails(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(_NavigateToProposalDetails value) - navigateToProposalDetails, - }) { - return navigateToProposalDetails(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(_NavigateToProposalDetails value)? - navigateToProposalDetails, - }) { - return navigateToProposalDetails?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(_NavigateToProposalDetails value)? - navigateToProposalDetails, - required TResult orElse(), - }) { - if (navigateToProposalDetails != null) { - return navigateToProposalDetails(this); - } - return orElse(); - } -} - -abstract class _NavigateToProposalDetails implements PageCommand { - const factory _NavigateToProposalDetails() = _$NavigateToProposalDetailsImpl; -} - /// @nodoc mixin _$ProposalDetailEvent { @optionalTypeArgs TResult when({ required TResult Function() initial, - required TResult Function() clearPageCommand, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? initial, - TResult? Function()? clearPageCommand, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeWhen({ TResult Function()? initial, - TResult Function()? clearPageCommand, required TResult orElse(), }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult map({ required TResult Function(_Initial value) initial, - required TResult Function(_ClearPageCommand value) clearPageCommand, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult? mapOrNull({ TResult? Function(_Initial value)? initial, - TResult? Function(_ClearPageCommand value)? clearPageCommand, }) => throw _privateConstructorUsedError; @optionalTypeArgs TResult maybeMap({ TResult Function(_Initial value)? initial, - TResult Function(_ClearPageCommand value)? clearPageCommand, required TResult orElse(), }) => throw _privateConstructorUsedError; @@ -284,7 +113,6 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult when({ required TResult Function() initial, - required TResult Function() clearPageCommand, }) { return initial(); } @@ -293,7 +121,6 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult? whenOrNull({ TResult? Function()? initial, - TResult? Function()? clearPageCommand, }) { return initial?.call(); } @@ -302,7 +129,6 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult maybeWhen({ TResult Function()? initial, - TResult Function()? clearPageCommand, required TResult orElse(), }) { if (initial != null) { @@ -315,7 +141,6 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult map({ required TResult Function(_Initial value) initial, - required TResult Function(_ClearPageCommand value) clearPageCommand, }) { return initial(this); } @@ -324,7 +149,6 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult? mapOrNull({ TResult? Function(_Initial value)? initial, - TResult? Function(_ClearPageCommand value)? clearPageCommand, }) { return initial?.call(this); } @@ -333,7 +157,6 @@ class _$InitialImpl implements _Initial { @optionalTypeArgs TResult maybeMap({ TResult Function(_Initial value)? initial, - TResult Function(_ClearPageCommand value)? clearPageCommand, required TResult orElse(), }) { if (initial != null) { @@ -347,117 +170,11 @@ abstract class _Initial implements ProposalDetailEvent { const factory _Initial() = _$InitialImpl; } -/// @nodoc -abstract class _$$ClearPageCommandImplCopyWith<$Res> { - factory _$$ClearPageCommandImplCopyWith(_$ClearPageCommandImpl value, - $Res Function(_$ClearPageCommandImpl) then) = - __$$ClearPageCommandImplCopyWithImpl<$Res>; -} - -/// @nodoc -class __$$ClearPageCommandImplCopyWithImpl<$Res> - extends _$ProposalDetailEventCopyWithImpl<$Res, _$ClearPageCommandImpl> - implements _$$ClearPageCommandImplCopyWith<$Res> { - __$$ClearPageCommandImplCopyWithImpl(_$ClearPageCommandImpl _value, - $Res Function(_$ClearPageCommandImpl) _then) - : super(_value, _then); - - /// Create a copy of ProposalDetailEvent - /// with the given fields replaced by the non-null parameter values. -} - -/// @nodoc - -class _$ClearPageCommandImpl implements _ClearPageCommand { - const _$ClearPageCommandImpl(); - - @override - String toString() { - return 'ProposalDetailEvent.clearPageCommand()'; - } - - @override - bool operator ==(Object other) { - return identical(this, other) || - (other.runtimeType == runtimeType && other is _$ClearPageCommandImpl); - } - - @override - int get hashCode => runtimeType.hashCode; - - @override - @optionalTypeArgs - TResult when({ - required TResult Function() initial, - required TResult Function() clearPageCommand, - }) { - return clearPageCommand(); - } - - @override - @optionalTypeArgs - TResult? whenOrNull({ - TResult? Function()? initial, - TResult? Function()? clearPageCommand, - }) { - return clearPageCommand?.call(); - } - - @override - @optionalTypeArgs - TResult maybeWhen({ - TResult Function()? initial, - TResult Function()? clearPageCommand, - required TResult orElse(), - }) { - if (clearPageCommand != null) { - return clearPageCommand(); - } - return orElse(); - } - - @override - @optionalTypeArgs - TResult map({ - required TResult Function(_Initial value) initial, - required TResult Function(_ClearPageCommand value) clearPageCommand, - }) { - return clearPageCommand(this); - } - - @override - @optionalTypeArgs - TResult? mapOrNull({ - TResult? Function(_Initial value)? initial, - TResult? Function(_ClearPageCommand value)? clearPageCommand, - }) { - return clearPageCommand?.call(this); - } - - @override - @optionalTypeArgs - TResult maybeMap({ - TResult Function(_Initial value)? initial, - TResult Function(_ClearPageCommand value)? clearPageCommand, - required TResult orElse(), - }) { - if (clearPageCommand != null) { - return clearPageCommand(this); - } - return orElse(); - } -} - -abstract class _ClearPageCommand implements ProposalDetailEvent { - const factory _ClearPageCommand() = _$ClearPageCommandImpl; -} - /// @nodoc mixin _$ProposalDetailState { PageState get pageState => throw _privateConstructorUsedError; - ProposalDetailsModel? get proposalDetails => + ProposalDetailsModel? get proposalDetailsModel => throw _privateConstructorUsedError; - PageCommand? get command => throw _privateConstructorUsedError; /// Create a copy of ProposalDetailState /// with the given fields replaced by the non-null parameter values. @@ -472,12 +189,7 @@ abstract class $ProposalDetailStateCopyWith<$Res> { ProposalDetailState value, $Res Function(ProposalDetailState) then) = _$ProposalDetailStateCopyWithImpl<$Res, ProposalDetailState>; @useResult - $Res call( - {PageState pageState, - ProposalDetailsModel? proposalDetails, - PageCommand? command}); - - $PageCommandCopyWith<$Res>? get command; + $Res call({PageState pageState, ProposalDetailsModel? proposalDetailsModel}); } /// @nodoc @@ -496,38 +208,19 @@ class _$ProposalDetailStateCopyWithImpl<$Res, $Val extends ProposalDetailState> @override $Res call({ Object? pageState = null, - Object? proposalDetails = freezed, - Object? command = freezed, + Object? proposalDetailsModel = freezed, }) { return _then(_value.copyWith( pageState: null == pageState ? _value.pageState : pageState // ignore: cast_nullable_to_non_nullable as PageState, - proposalDetails: freezed == proposalDetails - ? _value.proposalDetails - : proposalDetails // ignore: cast_nullable_to_non_nullable + proposalDetailsModel: freezed == proposalDetailsModel + ? _value.proposalDetailsModel + : proposalDetailsModel // ignore: cast_nullable_to_non_nullable as ProposalDetailsModel?, - command: freezed == command - ? _value.command - : command // ignore: cast_nullable_to_non_nullable - as PageCommand?, ) as $Val); } - - /// Create a copy of ProposalDetailState - /// with the given fields replaced by the non-null parameter values. - @override - @pragma('vm:prefer-inline') - $PageCommandCopyWith<$Res>? get command { - if (_value.command == null) { - return null; - } - - return $PageCommandCopyWith<$Res>(_value.command!, (value) { - return _then(_value.copyWith(command: value) as $Val); - }); - } } /// @nodoc @@ -538,13 +231,7 @@ abstract class _$$ProposalDetailStateImplCopyWith<$Res> __$$ProposalDetailStateImplCopyWithImpl<$Res>; @override @useResult - $Res call( - {PageState pageState, - ProposalDetailsModel? proposalDetails, - PageCommand? command}); - - @override - $PageCommandCopyWith<$Res>? get command; + $Res call({PageState pageState, ProposalDetailsModel? proposalDetailsModel}); } /// @nodoc @@ -561,22 +248,17 @@ class __$$ProposalDetailStateImplCopyWithImpl<$Res> @override $Res call({ Object? pageState = null, - Object? proposalDetails = freezed, - Object? command = freezed, + Object? proposalDetailsModel = freezed, }) { return _then(_$ProposalDetailStateImpl( pageState: null == pageState ? _value.pageState : pageState // ignore: cast_nullable_to_non_nullable as PageState, - proposalDetails: freezed == proposalDetails - ? _value.proposalDetails - : proposalDetails // ignore: cast_nullable_to_non_nullable + proposalDetailsModel: freezed == proposalDetailsModel + ? _value.proposalDetailsModel + : proposalDetailsModel // ignore: cast_nullable_to_non_nullable as ProposalDetailsModel?, - command: freezed == command - ? _value.command - : command // ignore: cast_nullable_to_non_nullable - as PageCommand?, )); } } @@ -585,19 +267,17 @@ class __$$ProposalDetailStateImplCopyWithImpl<$Res> class _$ProposalDetailStateImpl implements _ProposalDetailState { const _$ProposalDetailStateImpl( - {this.pageState = PageState.initial, this.proposalDetails, this.command}); + {this.pageState = PageState.initial, this.proposalDetailsModel}); @override @JsonKey() final PageState pageState; @override - final ProposalDetailsModel? proposalDetails; - @override - final PageCommand? command; + final ProposalDetailsModel? proposalDetailsModel; @override String toString() { - return 'ProposalDetailState(pageState: $pageState, proposalDetails: $proposalDetails, command: $command)'; + return 'ProposalDetailState(pageState: $pageState, proposalDetailsModel: $proposalDetailsModel)'; } @override @@ -607,14 +287,12 @@ class _$ProposalDetailStateImpl implements _ProposalDetailState { other is _$ProposalDetailStateImpl && (identical(other.pageState, pageState) || other.pageState == pageState) && - (identical(other.proposalDetails, proposalDetails) || - other.proposalDetails == proposalDetails) && - (identical(other.command, command) || other.command == command)); + (identical(other.proposalDetailsModel, proposalDetailsModel) || + other.proposalDetailsModel == proposalDetailsModel)); } @override - int get hashCode => - Object.hash(runtimeType, pageState, proposalDetails, command); + int get hashCode => Object.hash(runtimeType, pageState, proposalDetailsModel); /// Create a copy of ProposalDetailState /// with the given fields replaced by the non-null parameter values. @@ -628,16 +306,14 @@ class _$ProposalDetailStateImpl implements _ProposalDetailState { abstract class _ProposalDetailState implements ProposalDetailState { const factory _ProposalDetailState( - {final PageState pageState, - final ProposalDetailsModel? proposalDetails, - final PageCommand? command}) = _$ProposalDetailStateImpl; + {final PageState pageState, + final ProposalDetailsModel? proposalDetailsModel}) = + _$ProposalDetailStateImpl; @override PageState get pageState; @override - ProposalDetailsModel? get proposalDetails; - @override - PageCommand? get command; + ProposalDetailsModel? get proposalDetailsModel; /// Create a copy of ProposalDetailState /// with the given fields replaced by the non-null parameter values. diff --git a/lib/ui/proposals/details/interactor/proposal_detail_event.dart b/lib/ui/proposals/details/interactor/proposal_detail_event.dart index 0c76bdb4..1219aa8e 100644 --- a/lib/ui/proposals/details/interactor/proposal_detail_event.dart +++ b/lib/ui/proposals/details/interactor/proposal_detail_event.dart @@ -3,5 +3,4 @@ part of 'proposal_detail_bloc.dart'; @freezed class ProposalDetailEvent with _$ProposalDetailEvent { const factory ProposalDetailEvent.initial() = _Initial; - const factory ProposalDetailEvent.clearPageCommand() = _ClearPageCommand; } diff --git a/lib/ui/proposals/details/interactor/proposal_detail_state.dart b/lib/ui/proposals/details/interactor/proposal_detail_state.dart index 56a61f8c..cc5dfd44 100644 --- a/lib/ui/proposals/details/interactor/proposal_detail_state.dart +++ b/lib/ui/proposals/details/interactor/proposal_detail_state.dart @@ -4,7 +4,6 @@ part of 'proposal_detail_bloc.dart'; class ProposalDetailState with _$ProposalDetailState { const factory ProposalDetailState({ @Default(PageState.initial) PageState pageState, - ProposalDetailsModel? proposalDetails, - PageCommand? command, + ProposalDetailsModel? proposalDetailsModel, }) = _ProposalDetailState; } diff --git a/lib/ui/proposals/details/proposal_details_page.dart b/lib/ui/proposals/details/proposal_details_page.dart index feb7e8f9..a906fc16 100644 --- a/lib/ui/proposals/details/proposal_details_page.dart +++ b/lib/ui/proposals/details/proposal_details_page.dart @@ -1,15 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get_it/get_it.dart'; -import 'package:hypha_wallet/core/network/models/proposal_model.dart'; -import 'package:hypha_wallet/core/network/repository/proposal_repository.dart'; -import 'package:hypha_wallet/ui/proposals/details/components/proposal_detail_view.dart'; +import 'package:hypha_wallet/core/error_handler/error_handler_manager.dart'; +import 'package:hypha_wallet/ui/proposals/details/components/proposal_details_view.dart'; import 'package:hypha_wallet/ui/proposals/details/interactor/proposal_detail_bloc.dart'; import 'package:hypha_wallet/ui/proposals/details/usecases/get_proposal_details_use_case.dart'; -import '../../../core/error_handler/error_handler_manager.dart'; -import '../../../core/network/repository/auth_repository.dart'; - class ProposalDetailsPage extends StatelessWidget { final String proposalId; @@ -18,17 +14,9 @@ class ProposalDetailsPage extends StatelessWidget { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => ProposalDetailBloc(proposalId,GetProposalDetailsUseCase(GetIt.I.get(),GetIt.I.get()),GetIt.I.get())..add(const ProposalDetailEvent.initial()), - child: BlocListener( - listenWhen: (previous, current) => previous.command != current.command, - listener: (context, state) { - state.command?.when( - navigateToProposalDetails: () {}, - ); - context.read().add(const ProposalDetailEvent.clearPageCommand()); - }, - child: ProposalDetailView(), - ), + create: (context) => ProposalDetailBloc(proposalId, GetIt.I.get(), GetIt.I.get()) + ..add(const ProposalDetailEvent.initial()), + child: const ProposalDetailsView() ); } } diff --git a/lib/ui/proposals/list/components/hypha_proposals_action_card.dart b/lib/ui/proposals/list/components/hypha_proposals_action_card.dart index e1177347..4c4ee13f 100644 --- a/lib/ui/proposals/list/components/hypha_proposals_action_card.dart +++ b/lib/ui/proposals/list/components/hypha_proposals_action_card.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:get/get.dart' as Get; -import 'package:hypha_wallet/core/extension/proposal_model_extensions.dart'; +import 'package:hypha_wallet/core/extension/base_proposal_model_extension.dart'; import 'package:hypha_wallet/core/network/models/proposal_model.dart'; import 'package:hypha_wallet/core/network/models/vote_model.dart'; import 'package:hypha_wallet/design/dividers/hypha_divider.dart'; @@ -33,7 +33,7 @@ class HyphaProposalsActionCard extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ ProposalHeader( - proposalModel.daoName, + proposalModel.daoName ?? '', 'https://etudestech.com/wp-content/uploads/2023/05/midjourney-scaled.jpeg', ), const Padding( @@ -43,7 +43,7 @@ class HyphaProposalsActionCard extends StatelessWidget { _buildProposalRoleAssignment( context, proposalModel.commitment ?? 0, - proposalModel.title ?? 'No title set for this proposal.', + proposalModel.title ?? 'No title', ), Padding( padding: const EdgeInsets.symmetric(vertical: 20), @@ -126,6 +126,7 @@ class HyphaProposalsActionCard extends StatelessWidget { children: [ Row( children: [ + // TODO(Zied-Saif): figure these out (B6 and Role) _buildProposalInfoText(context, 'Role Assignment'), _buildProposalInfoText(context, 'B6'), _buildProposalInfoText(context, '$commitment%'), From f34d1536238763cd71310ac0e50e8f4e74662921 Mon Sep 17 00:00:00 2001 From: Zied Dahmani Date: Tue, 10 Sep 2024 18:21:44 +0100 Subject: [PATCH 2/2] refactor: swap cash and utility tokens --- .../proposal_details_model_extension.dart | 11 +++++---- .../models/proposal_details_model.dart | 8 +++---- .../models/proposal_details_model.g.dart | 17 +++++++------- .../components/proposal_details_view.dart | 23 +++++++++++-------- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/lib/core/extension/proposal_details_model_extension.dart b/lib/core/extension/proposal_details_model_extension.dart index 4e2b8329..6868fb1a 100644 --- a/lib/core/extension/proposal_details_model_extension.dart +++ b/lib/core/extension/proposal_details_model_extension.dart @@ -13,13 +13,13 @@ extension ProposalDetailsModelExtension on ProposalDetailsModel { switch (index) { case 0: - input = cashAmount ?? cashAmountPerPeriod!; + input = utilityAmount ?? utilityAmountPerPeriod!; break; case 1: input = voiceAmount ?? voiceAmountPerPeriod!; break; case 2: - input = utilityAmount ?? utilityAmountPerPeriod!; + input = cashAmount ?? cashAmountPerPeriod!; break; default: return null; @@ -39,18 +39,19 @@ extension ProposalDetailsModelExtension on ProposalDetailsModel { return null; } - String? tokenValue(int index) { + // TODO(Saif): adjust this function + String? tokenValue(int index, bool isOneCycleRewardsShown) { String input; switch (index) { case 0: - input = cashAmount ?? cashAmountPerPeriod!; + input = utilityAmount ?? utilityAmountPerPeriod!; break; case 1: input = voiceAmount ?? voiceAmountPerPeriod!; break; case 2: - input = utilityAmount ?? utilityAmountPerPeriod!; + input = cashAmount ?? cashAmountPerPeriod!; break; default: return null; diff --git a/lib/core/network/models/proposal_details_model.dart b/lib/core/network/models/proposal_details_model.dart index ce14b160..9819abb9 100644 --- a/lib/core/network/models/proposal_details_model.dart +++ b/lib/core/network/models/proposal_details_model.dart @@ -21,22 +21,22 @@ class ProposalDetailsModel extends BaseProposalModel { @JsonKey(name: 'start') final DateTime? cycleStartDate; - @JsonKey(name: 'details_pegAmount_a') + @JsonKey(name: 'details_rewardAmount_a') final String? utilityAmount; @JsonKey(name: 'details_voiceAmount_a') final String? voiceAmount; - @JsonKey(name: 'details_rewardAmount_a') + @JsonKey(name: 'details_pegAmount_a') final String? cashAmount; - @JsonKey(name: 'details_pegSalaryPerPeriod_a') + @JsonKey(name: 'details_rewardSalaryPerPeriod_a') final String? utilityAmountPerPeriod; @JsonKey(name: 'details_voiceSalaryPerPeriod_a') final String? voiceAmountPerPeriod; - @JsonKey(name: 'details_rewardSalaryPerPeriod_a') + @JsonKey(name: 'details_pegSalaryPerPeriod_a') final String? cashAmountPerPeriod; @JsonKey(name: 'details_description_s') diff --git a/lib/core/network/models/proposal_details_model.g.dart b/lib/core/network/models/proposal_details_model.g.dart index 1121ce3f..dedb9d16 100644 --- a/lib/core/network/models/proposal_details_model.g.dart +++ b/lib/core/network/models/proposal_details_model.g.dart @@ -29,12 +29,13 @@ ProposalDetailsModel _$ProposalDetailsModelFromJson( cycleStartDate: json['start'] == null ? null : DateTime.parse(json['start'] as String), - utilityAmount: json['details_pegAmount_a'] as String?, + utilityAmount: json['details_rewardAmount_a'] as String?, voiceAmount: json['details_voiceAmount_a'] as String?, - cashAmount: json['details_rewardAmount_a'] as String?, - utilityAmountPerPeriod: json['details_pegSalaryPerPeriod_a'] as String?, + cashAmount: json['details_pegAmount_a'] as String?, + utilityAmountPerPeriod: + json['details_rewardSalaryPerPeriod_a'] as String?, voiceAmountPerPeriod: json['details_voiceSalaryPerPeriod_a'] as String?, - cashAmountPerPeriod: json['details_rewardSalaryPerPeriod_a'] as String?, + cashAmountPerPeriod: json['details_pegSalaryPerPeriod_a'] as String?, description: json['details_description_s'] as String?, ); @@ -55,11 +56,11 @@ Map _$ProposalDetailsModelToJson( 'details_deferredPercX100_i': instance.tokenMixPercentage, 'details_periodCount_i': instance.cycleCount, 'start': instance.cycleStartDate?.toIso8601String(), - 'details_pegAmount_a': instance.utilityAmount, + 'details_rewardAmount_a': instance.utilityAmount, 'details_voiceAmount_a': instance.voiceAmount, - 'details_rewardAmount_a': instance.cashAmount, - 'details_pegSalaryPerPeriod_a': instance.utilityAmountPerPeriod, + 'details_pegAmount_a': instance.cashAmount, + 'details_rewardSalaryPerPeriod_a': instance.utilityAmountPerPeriod, 'details_voiceSalaryPerPeriod_a': instance.voiceAmountPerPeriod, - 'details_rewardSalaryPerPeriod_a': instance.cashAmountPerPeriod, + 'details_pegSalaryPerPeriod_a': instance.cashAmountPerPeriod, 'details_description_s': instance.description, }; diff --git a/lib/ui/proposals/details/components/proposal_details_view.dart b/lib/ui/proposals/details/components/proposal_details_view.dart index d9cbb310..df92f7e9 100644 --- a/lib/ui/proposals/details/components/proposal_details_view.dart +++ b/lib/ui/proposals/details/components/proposal_details_view.dart @@ -29,7 +29,7 @@ class ProposalDetailsView extends StatefulWidget { } class _ProposalDetailsViewState extends State { - final ValueNotifier _isShownNotifier = ValueNotifier(true); + final ValueNotifier _isShownNotifier = ValueNotifier(null); final ValueNotifier _isOverflowingNotifier = ValueNotifier(false); final ValueNotifier _isExpandedNotifier = ValueNotifier(false); final ValueNotifier _detailsNotifier = ValueNotifier(null); @@ -46,6 +46,10 @@ class _ProposalDetailsViewState extends State { } } + void _initSwitchValue(ProposalDetailsModel proposalDetailsModel) { + _isShownNotifier.value = proposalDetailsModel.utilityAmount != null; + } + @override Widget build(BuildContext context) { return HyphaPageBackground( @@ -65,6 +69,7 @@ class _ProposalDetailsViewState extends State { _detailsNotifier.value = _proposalDetailsModel.description; WidgetsBinding.instance.addPostFrameCallback((_) { _checkIfTextIsOverflowing(); + _initSwitchValue(_proposalDetailsModel); }); return Padding( padding: const EdgeInsets.symmetric(horizontal: 30), @@ -162,9 +167,9 @@ class _ProposalDetailsViewState extends State { /// Rewards Section // TODO(Zied): implement the logic if (!(_proposalDetailsModel.utilityAmount == null && _proposalDetailsModel.utilityAmountPerPeriod == null)) ... [ - ValueListenableBuilder( + ValueListenableBuilder( valueListenable: _isShownNotifier, - builder: (context, isShown, child) { + builder: (BuildContext context, bool? isShown, Widget? child) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -202,7 +207,7 @@ class _ProposalDetailsViewState extends State { ), const SizedBox(width: 10), Text( - _proposalDetailsModel.tokenValue(index) ?? '', + _proposalDetailsModel.tokenValue(index, isShown ?? false) ?? '', style: context.hyphaTextTheme.bigTitles.copyWith(fontWeight: FontWeight.normal), ) ], @@ -224,15 +229,15 @@ class _ProposalDetailsViewState extends State { ), ), const SizedBox(width: 10), - ValueListenableBuilder( + ValueListenableBuilder( valueListenable: _isShownNotifier, - builder: (BuildContext context, bool value, Widget? child) { - return Switch( - value: value, + builder: (BuildContext context, bool? value, Widget? child) { + return _isShownNotifier.value != null ? Switch( + value: value!, onChanged: (newValue) { _isShownNotifier.value = newValue; }, - ); + ) : const SizedBox.shrink(); }, ), ],