From e1eab667063383cb7523574287c4e7b6178ee69a Mon Sep 17 00:00:00 2001 From: MarkG Date: Fri, 14 May 2021 09:28:24 +0700 Subject: [PATCH] feat: integrate survey detail (#28) --- lib/modules/home/components/body.dart | 1 + lib/modules/home/home_router.dart | 5 +- .../survey_detail/components/content.dart | 123 +++++++++++------- .../survey_detail_interactor.dart | 30 ++++- .../survey_detail/survey_detail_module.dart | 22 +++- .../survey_detail_presenter.dart | 48 ++++++- .../survey_detail/survey_detail_router.dart | 11 +- .../survey_detail/survey_detail_view.dart | 33 ++++- test/modules/home/home_router_test.dart | 6 +- 9 files changed, 213 insertions(+), 66 deletions(-) diff --git a/lib/modules/home/components/body.dart b/lib/modules/home/components/body.dart index 8f78b7f0..ad32a8de 100644 --- a/lib/modules/home/components/body.dart +++ b/lib/modules/home/components/body.dart @@ -41,6 +41,7 @@ class Body extends StatelessWidget { isShown: isLoading, baseColor: Colors.white.withOpacity(0.12), highlightColor: Colors.white.withOpacity(0.5), + transition: BoneTransition.none, child: child!, ), child: Stack( diff --git a/lib/modules/home/home_router.dart b/lib/modules/home/home_router.dart index 406a037c..87ea44cb 100644 --- a/lib/modules/home/home_router.dart +++ b/lib/modules/home/home_router.dart @@ -9,6 +9,9 @@ class HomeRouterImpl extends HomeRouter { @override void pushToSurveyDetail( {required BuildContext context, required SurveyInfo survey}) { - context.navigator.pushNamed(SurveyDetailModule.routePath); + context.navigator.pushNamed( + SurveyDetailModule.routePath, + arguments: SurveyDetailArguments(survey: survey), + ); } } diff --git a/lib/modules/survey_detail/components/content.dart b/lib/modules/survey_detail/components/content.dart index 75462d3a..4654d933 100644 --- a/lib/modules/survey_detail/components/content.dart +++ b/lib/modules/survey_detail/components/content.dart @@ -5,62 +5,85 @@ class Content extends StatelessWidget { @override Widget build(BuildContext context) { - return Screen( - body: Stack( - fit: StackFit.expand, - children: [ - Image( - image: Assets.images.mainBackgroundDimmed, - fit: BoxFit.fill, - ), - SafeArea( - child: Column( - children: [ - NavigationBar(), - Expanded( - child: Container( - margin: const EdgeInsets.fromLTRB(20, 0, 20, 0), - child: Column( - children: [ - const Text( - "Working from home Check-In", - style: TextStyle( - color: Colors.white, - fontSize: 34, + final state = + context.findAncestorStateOfType<_SurveyDetailViewImplState>()!; + + return StreamsSelector0.value( + stream: state.isProgressHUDShown, + builder: (_, isShown, child) => ProgressHUD( + isShow: isShown, + child: child!, + ), + child: Screen( + body: Stack( + fit: StackFit.expand, + children: [ + StreamsSelector0.value( + stream: state._survey, + builder: (_, survey, __) => Image( + image: NetworkImage(survey.coverImageUrl!), + fit: BoxFit.fill, + ), + ), + SafeArea( + child: Column( + children: [ + NavigationBar(), + Expanded( + child: Container( + margin: const EdgeInsets.fromLTRB(20, 0, 20, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + StreamsSelector0.value( + stream: state._survey, + builder: (_, survey, __) => Text( + survey.title!, + style: const TextStyle( + color: Colors.white, + fontSize: 34, + ), + ), ), - ), - const SizedBox( - height: 17, - ), - Text( - "We would like to know how you feel about our work from home (WFH) experience.", - style: TextStyle( - color: Colors.white.withOpacity(0.7), - fontSize: 17, + const SizedBox( + height: 17, ), - ), - Expanded(child: Container()), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - ConstrainedBox( - constraints: const BoxConstraints( - minWidth: 140, - ), - child: Button( - title: AppLocalizations.of(context)! - .surveyDetailScreenStartSurveyButtonTitle, - ), + StreamsSelector0.value( + stream: state._survey, + builder: (_, survey, __) => Text( + survey.description!, + style: TextStyle( + color: Colors.white.withOpacity(0.7), + fontSize: 17, ), - ]), - ], + ), + ), + Expanded(child: Container()), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + ConstrainedBox( + constraints: const BoxConstraints( + minWidth: 140, + ), + child: Button( + onPressed: () => state + .delegate?.startSurveyButtonDidTap + .add(null), + title: AppLocalizations.of(context)! + .surveyDetailScreenStartSurveyButtonTitle, + ), + ), + ]), + ], + ), ), ), - ), - ], + ], + ), ), - ), - ], + ], + ), ), ); } diff --git a/lib/modules/survey_detail/survey_detail_interactor.dart b/lib/modules/survey_detail/survey_detail_interactor.dart index 62097065..690763ad 100644 --- a/lib/modules/survey_detail/survey_detail_interactor.dart +++ b/lib/modules/survey_detail/survey_detail_interactor.dart @@ -1,8 +1,30 @@ part of 'survey_detail_module.dart'; -abstract class SurveyDetailInteractorDelegate {} +abstract class SurveyDetailInteractorDelegate { + BehaviorSubject get detailedSurveyDidFetch; -abstract class SurveyDetailInteractor - extends Interactor {} + BehaviorSubject get detailedSurveyDidFailToFetch; +} -class SurveyDetailInteractorImpl extends SurveyDetailInteractor {} +abstract class SurveyDetailInteractor extends ArgumentsInteractor< + SurveyDetailInteractorDelegate, SurveyDetailArguments> { + SurveyInfo get survey; + + void fetchDetailedSurvey(); +} + +class SurveyDetailInteractorImpl extends SurveyDetailInteractor { + final SurveyRepository _surveyRepository = locator.get(); + + @override + SurveyInfo get survey => arguments!.survey; + + @override + void fetchDetailedSurvey() { + _surveyRepository + .fetchDetailedSurvey(survey.id!) + .then((value) => delegate?.detailedSurveyDidFetch.add(value)) + .onError((exception, _) => + delegate?.detailedSurveyDidFailToFetch.add(exception)); + } +} diff --git a/lib/modules/survey_detail/survey_detail_module.dart b/lib/modules/survey_detail/survey_detail_module.dart index bfc60933..201efe2b 100644 --- a/lib/modules/survey_detail/survey_detail_module.dart +++ b/lib/modules/survey_detail/survey_detail_module.dart @@ -1,11 +1,17 @@ import 'package:flutter/material.dart' hide Router; import 'package:flutter/widgets.dart' hide Router; +import 'package:streams_provider/streams_provider.dart'; +import 'package:survey/components/alert/alert.dart'; import 'package:survey/components/button/button.dart'; +import 'package:survey/components/common/progress_hud.dart'; import 'package:survey/components/navigation_bar/navigation_bar.dart'; import 'package:survey/core/viper/module.dart'; -import 'package:survey/gen/assets.gen.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:survey/models/detailed_survey_info.dart'; +import 'package:survey/models/survey_info.dart'; import 'package:survey/modules/screen.dart'; +import 'package:survey/repositories/survey_repository.dart'; +import 'package:survey/services/locator/locator_service.dart'; part 'survey_detail_view.dart'; @@ -17,8 +23,12 @@ part 'survey_detail_router.dart'; part 'components/content.dart'; -class SurveyDetailModule extends Module { +class SurveyDetailModule extends ArgumentsModule< + SurveyDetailView, + SurveyDetailInteractor, + SurveyDetailPresenter, + SurveyDetailRouter, + SurveyDetailArguments> { static const routePath = "/survey/detail"; @override @@ -26,3 +36,9 @@ class SurveyDetailModule extends Module {} class SurveyDetailPresenterImpl extends SurveyDetailPresenter - implements SurveyDetailViewDelegate, SurveyDetailInteractorDelegate {} + implements SurveyDetailViewDelegate, SurveyDetailInteractorDelegate { + SurveyDetailPresenterImpl() { + stateDidInit.voidListen(_stateDidInit).addTo(disposeBag); + startSurveyButtonDidTap + .voidListen(_startSurveyButtonDidTap) + .addTo(disposeBag); + + detailedSurveyDidFetch.listen(_detailedSurveyDidFetch).addTo(disposeBag); + detailedSurveyDidFailToFetch + .listen(_detailedSurveyDidFailToFetch) + .addTo(disposeBag); + } + + @override + final detailedSurveyDidFailToFetch = BehaviorSubject(); + + @override + final detailedSurveyDidFetch = BehaviorSubject(); + + @override + final alertDialogDidClose = BehaviorSubject(); + + @override + final stateDidInit = BehaviorSubject(); + + @override + final startSurveyButtonDidTap = BehaviorSubject(); + + void _stateDidInit() { + view.setSurvey(interactor.survey); + } + + void _startSurveyButtonDidTap() { + view.showProgressHUD(); + interactor.fetchDetailedSurvey(); + } + + void _detailedSurveyDidFetch(DetailedSurveyInfo survey) { + view.dismissProgressHUD(); + router.pushToSurveyQuestionsScreen(view.context, survey: survey); + } + + void _detailedSurveyDidFailToFetch(Exception exception) { + view.dismissProgressHUD(); + view.alert(exception); + } +} diff --git a/lib/modules/survey_detail/survey_detail_router.dart b/lib/modules/survey_detail/survey_detail_router.dart index 1a5259e8..67b8b080 100644 --- a/lib/modules/survey_detail/survey_detail_router.dart +++ b/lib/modules/survey_detail/survey_detail_router.dart @@ -1,5 +1,12 @@ part of 'survey_detail_module.dart'; -abstract class SurveyDetailRouter extends Router {} +abstract class SurveyDetailRouter extends Router { + void pushToSurveyQuestionsScreen(BuildContext context, + {required DetailedSurveyInfo survey}); +} -class SurveyDetailRouterImpl extends SurveyDetailRouter {} +class SurveyDetailRouterImpl extends SurveyDetailRouter { + @override + void pushToSurveyQuestionsScreen(BuildContext context, + {required DetailedSurveyInfo survey}) {} +} diff --git a/lib/modules/survey_detail/survey_detail_view.dart b/lib/modules/survey_detail/survey_detail_view.dart index d77600c5..b070fd69 100644 --- a/lib/modules/survey_detail/survey_detail_view.dart +++ b/lib/modules/survey_detail/survey_detail_view.dart @@ -1,8 +1,15 @@ part of 'survey_detail_module.dart'; -abstract class SurveyDetailViewDelegate {} +abstract class SurveyDetailViewDelegate implements AlertViewMixinDelegate { + BehaviorSubject get stateDidInit; -abstract class SurveyDetailView extends View {} + BehaviorSubject get startSurveyButtonDidTap; +} + +abstract class SurveyDetailView extends View + with ProgressHUDViewMixin, AlertViewMixin { + void setSurvey(SurveyInfo survey); +} class SurveyDetailViewImpl extends StatefulWidget { const SurveyDetailViewImpl({Key? key}) : super(key: key); @@ -12,9 +19,29 @@ class SurveyDetailViewImpl extends StatefulWidget { } class _SurveyDetailViewImplState extends ViewState implements SurveyDetailView { + SurveyDetailModule, SurveyDetailViewDelegate> + with ProgressHUDViewMixin, AlertViewMixin + implements SurveyDetailView { + late final _survey = BehaviorSubject(); + + @override + void initState() { + super.initState(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + delegate?.stateDidInit.add(null); + } + @override Widget build(BuildContext context) { return const Content(); } + + @override + void setSurvey(SurveyInfo survey) { + _survey.add(survey); + } } diff --git a/test/modules/home/home_router_test.dart b/test/modules/home/home_router_test.dart index 357b2eeb..fb72efe7 100644 --- a/test/modules/home/home_router_test.dart +++ b/test/modules/home/home_router_test.dart @@ -26,12 +26,14 @@ void main() { beforeEach(() { when(buildContext.findAncestorStateOfType()) .thenReturn(navigatorState); - when(navigatorState.pushNamed(any)).thenAnswer((_) => Future.value()); + when(navigatorState.pushNamed(any, arguments: anyNamed("arguments"))) + .thenAnswer((_) => Future.value()); router.pushToSurveyDetail(context: buildContext, survey: SurveyInfo()); }); it("triggers navigator to push to Survey Detail screen", () { - final routePath = verify(navigatorState.pushNamed(captureAny)) + final routePath = verify(navigatorState.pushNamed(captureAny, + arguments: anyNamed("arguments"))) .captured .single as String; expect(routePath, SurveyDetailModule.routePath);