Skip to content

Commit

Permalink
feat: implement proposal review page
Browse files Browse the repository at this point in the history
  • Loading branch information
Zied-Dahmani committed Oct 9, 2024
1 parent d2a0f94 commit d5e0363
Show file tree
Hide file tree
Showing 14 changed files with 1,276 additions and 64 deletions.
2 changes: 2 additions & 0 deletions lib/core/di/bloc_module.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,6 @@ void _registerBlocsModule() {
dao
),
);

_registerFactory(() => ProposalCreationBloc());
}
1 change: 1 addition & 0 deletions lib/core/di/di_setup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,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/creation/interactor/proposal_creation_bloc.dart';
import 'package:hypha_wallet/ui/proposals/details/usecases/get_proposal_details_use_case.dart';
import 'package:hypha_wallet/ui/proposals/filter/interactor/filter_proposals_bloc.dart';
import 'package:hypha_wallet/ui/proposals/filter/usecases/aggregate_dao_proposal_counts_use_case.dart';
Expand Down
13 changes: 13 additions & 0 deletions lib/core/network/models/proposal_creation_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class ProposalCreationModel {
final String? title;
final String? details;

ProposalCreationModel({this.title, this.details});

ProposalCreationModel copyWith(Map<String, dynamic> updates) {
return ProposalCreationModel(
title: updates.containsKey('title') ? updates['title'] : title,
details: updates.containsKey('details') ? updates['details'] : details,
);
}
}
13 changes: 8 additions & 5 deletions lib/ui/proposals/components/proposal_header.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import 'package:flutter/material.dart';
import 'package:hypha_wallet/core/network/models/dao_data_model.dart';
import 'package:hypha_wallet/design/dao_image.dart';
import 'package:hypha_wallet/design/hypha_colors.dart';
import 'package:hypha_wallet/design/themes/extensions/theme_extension_provider.dart';

class ProposalHeader extends StatelessWidget {
final DaoData? _dao;
const ProposalHeader(this._dao, {super.key});
final String? _text;

// TODO(Zied-Saif): figure this out
const ProposalHeader(this._dao, {String text = 'Marketing Circle', super.key}) : _text = text;

@override
Widget build(BuildContext context) {
Expand All @@ -16,15 +20,14 @@ class ProposalHeader extends StatelessWidget {
Flexible(
child: Text(
_dao?.settingsDaoTitle ?? '',
style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(fontWeight: FontWeight.bold),
style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(fontWeight: FontWeight.bold, color: HyphaColors.offWhite),
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 10),
// TODO(Zied-Saif): figure this out
Text(
'Marketing Circle',
style: context.hyphaTextTheme.ralMediumSmallNote,
_text!,
style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.midGrey),
),
],
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:get/get_utils/src/extensions/context_extensions.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/creation/interactor/proposal_creation_bloc.dart';

class ProposalCreationView extends StatefulWidget {
const ProposalCreationView({super.key});
class ProposalContentView extends StatefulWidget {
const ProposalContentView({super.key});

@override
State<ProposalCreationView> createState() => _ProposalCreationViewState();
State<ProposalContentView> createState() => _ProposalContentViewState();
}

class _ProposalCreationViewState extends State<ProposalCreationView> {
class _ProposalContentViewState extends State<ProposalContentView> {
final TextEditingController _titleController = TextEditingController();
final QuillController _quillController = QuillController.basic();
final ScrollController _scrollController = ScrollController();
Expand All @@ -22,6 +25,10 @@ class _ProposalCreationViewState extends State<ProposalCreationView> {
void initState() {
super.initState();

_titleController.addListener(() {
context.read<ProposalCreationBloc>().add(ProposalCreationEvent.updateProposal({'title': _titleController.text.isEmpty ? null : _titleController.text}));
});

_focusNode.addListener(() {
_isEditingNotifier.value = _focusNode.hasFocus;
if (_focusNode.hasFocus) {
Expand All @@ -30,6 +37,9 @@ class _ProposalCreationViewState extends State<ProposalCreationView> {
});

_quillController.document.changes.listen((event) {
final String plainText = _quillController.document.toPlainText();
final String json = jsonEncode(_quillController.document.toDelta().toJson());
context.read<ProposalCreationBloc>().add(ProposalCreationEvent.updateProposal({'details': plainText.length == 1 ? null : json}));
_scrollToBottom();
});
}
Expand Down Expand Up @@ -87,10 +97,12 @@ class _ProposalCreationViewState extends State<ProposalCreationView> {
decoration: InputDecoration(
filled: true,
fillColor: context.isDarkMode ? HyphaColors.lightBlack : HyphaColors.white,
hintText: 'Your Proposal Title',
hintStyle: context.hyphaTextTheme.ralMediumBody.copyWith(color: HyphaColors.midGrey),
labelText: 'Title',
labelStyle: TextStyle(
color: _titleController.text.isEmpty
? (context.isDarkMode ? HyphaColors.midGrey : HyphaColors.black)
? (context.isDarkMode ? HyphaColors.offWhite : HyphaColors.black)
: HyphaColors.primaryBlu,
),
floatingLabelBehavior: FloatingLabelBehavior.always,
Expand Down Expand Up @@ -147,6 +159,27 @@ class _ProposalCreationViewState extends State<ProposalCreationView> {
),
),
),
Positioned.fill(
child: GestureDetector(
onTap: () {
_focusNode.requestFocus();
},
child: StreamBuilder(
stream: _quillController.document.changes,
builder: (context, snapshot) {
return _quillController.document.isEmpty()
? Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 6.0),
child: Text(
'Your Proposal Details',
style: context.hyphaTextTheme.ralMediumBody.copyWith(color: HyphaColors.midGrey),
),
)
: const SizedBox.shrink();
},
),
),
),
Positioned(
left: 12,
top: -6,
Expand All @@ -155,7 +188,7 @@ class _ProposalCreationViewState extends State<ProposalCreationView> {
style: context.hyphaTextTheme.ralMediumLabel.copyWith(
color: _quillController.document.isEmpty()
? (context.isDarkMode
? HyphaColors.midGrey
? HyphaColors.offWhite
: HyphaColors.black)
: HyphaColors.primaryBlu,
),
Expand Down
107 changes: 107 additions & 0 deletions lib/ui/proposals/creation/components/proposal_review_view.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/quill_delta.dart';
import 'package:get/get_utils/src/extensions/context_extensions.dart';
import 'package:hypha_wallet/core/network/models/dao_data_model.dart';
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_header.dart';
import 'package:hypha_wallet/ui/proposals/creation/interactor/proposal_creation_bloc.dart';

class ProposalReviewView extends StatelessWidget {
const ProposalReviewView({super.key});

@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 20),
height: double.infinity,
color: context.isDarkMode ? HyphaColors.darkBlack : HyphaColors.offWhite,
child: SafeArea(
bottom: true,
child: LayoutBuilder(
builder: (context, constraint) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraint.maxHeight),
child: IntrinsicHeight(
child: BlocBuilder<ProposalCreationBloc, ProposalCreationState>(
builder: (context, state) {
final List<dynamic> jsonData = jsonDecode(state.proposal!.details!);
final Document document = Document.fromDelta(Delta.fromJson(jsonData));

return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 20),
const Row(
children: [
Expanded(
child: ProposalHeader(
DaoData(
docId: 21345,
detailsDaoName: '',
settingsDaoTitle: 'HyphaDao',
logoIPFSHash: '',
logoType: '',
settingsDaoUrl: '',
),
text: 'Builders',
),
),
SizedBox(width: 10),
Icon(CupertinoIcons.hand_thumbsup, color: HyphaColors.primaryBlu),
],
),
const Padding(
padding: EdgeInsets.only(top: 10, bottom: 20),
child: HyphaDivider(),
),
Text(
'Agreement for',
style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.primaryBlu),
),
Padding(
padding: const EdgeInsets.only(top: 10, bottom: 20),
child: Text(
state.proposal!.title!,
style: context.hyphaTextTheme.mediumTitles,
),
),
Text(
'Details',
style: context.hyphaTextTheme.ralMediumSmallNote.copyWith(color: HyphaColors.primaryBlu),
),
Padding(
padding: const EdgeInsets.only(top: 10, bottom: 20),
child: QuillEditor.basic(
controller: QuillController(
document: document,
selection: const TextSelection.collapsed(offset: 0),
readOnly: true,
),
),
),
const Spacer(),
HyphaAppButton(
title: 'Publish',
onPressed: () async {
},
),
],
);
},
),
),
),
);
}
),
),
);
}
}
6 changes: 6 additions & 0 deletions lib/ui/proposals/creation/interactor/page_command.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
part of 'proposal_creation_bloc.dart';

@freezed
class PageCommand with _$PageCommand {
const factory PageCommand.navigateBackToProposals() = _NavigateBackToProposals;
}
68 changes: 68 additions & 0 deletions lib/ui/proposals/creation/interactor/proposal_creation_bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:hypha_wallet/core/network/models/proposal_creation_model.dart';
import 'package:hypha_wallet/core/network/models/proposal_details_model.dart';
import 'package:hypha_wallet/ui/architecture/interactor/page_states.dart';

part 'page_command.dart';
part 'proposal_creation_bloc.freezed.dart';
part 'proposal_creation_event.dart';
part 'proposal_creation_state.dart';

class ProposalCreationBloc
extends Bloc<ProposalCreationEvent, ProposalCreationState> {
ProposalCreationBloc() : super(ProposalCreationState(proposal: ProposalCreationModel())) {
on<_UpdateCurrentView>(_updateCurrentView);
on<_UpdateProposal>(_updateProposal);
on<_ClearPageCommand>((_, emit) => emit(state.copyWith(command: null)));
}

// TODO(Saif): pass initialPage as parameter
final PageController _pageController = PageController(initialPage: 0);
PageController get pageController => _pageController;

Future<void> _updateCurrentView(_UpdateCurrentView event, Emitter<ProposalCreationState> emit) async {
if (event.nextViewIndex == -1) {
emit(state.copyWith(command: const PageCommand.navigateBackToProposals()));
} else {
switch (event.nextViewIndex) {
case 0:
navigate(emit, event.nextViewIndex);
break;
case 1:
navigate(emit, event.nextViewIndex);
break;
case 2:
if(state.proposal?.details != null) {
navigate(emit, event.nextViewIndex);
}
break;
case 3:
navigate(emit, event.nextViewIndex);
break;
case 4:
navigate(emit, event.nextViewIndex);
break;
default:
break;
}
}
}

void navigate(Emitter<ProposalCreationState> emit, int nextIndex) {
emit(state.copyWith(currentViewIndex: nextIndex));
_pageController.animateToPage(
nextIndex,
duration: const Duration(milliseconds: 200),
curve: Curves.easeInOut,
);
}

Future<void> _updateProposal(_UpdateProposal event, Emitter<ProposalCreationState> emit) async {
final ProposalCreationModel? proposal = state.proposal?.copyWith(event.updates);
if (proposal != null) {
emit(state.copyWith(proposal: proposal));
}
}
}
Loading

0 comments on commit d5e0363

Please sign in to comment.