Line data Source code
1 : import 'package:cached_network_image/cached_network_image.dart';
2 : import 'package:flutter/material.dart';
3 : import 'package:flutter/services.dart';
4 : import 'package:google_fonts/google_fonts.dart';
5 : import 'package:mvvm_builder/mvvm_builder.dart';
6 : import 'package:pal/src/ui/client/widgets/animated/animated_scale.dart';
7 : import 'package:pal/src/ui/client/widgets/animated/animated_translate.dart';
8 : import 'package:pal/src/ui/shared/helper_shared_viewmodels.dart';
9 :
10 : import 'user_fullscreen_helper_presenter.dart';
11 : import 'user_fullscreen_helper_viewmodel.dart';
12 :
13 : abstract class UserFullScreenHelperView {
14 : void playAnimation(
15 : MvvmContext context,
16 : bool isReversed,
17 : int index,
18 : Function callback,
19 : );
20 : void onPositivButtonCallback();
21 : void onNegativButtonCallback();
22 : }
23 :
24 : class UserFullScreenHelperPage extends StatelessWidget
25 : implements UserFullScreenHelperView {
26 : final HelperBoxViewModel helperBoxViewModel;
27 : final HelperTextViewModel titleLabel;
28 : final HelperTextViewModel positivLabel;
29 : final HelperTextViewModel negativLabel;
30 : final HelperImageViewModel headerImageViewModel;
31 : final Function onPositivButtonTap;
32 : final Function onNegativButtonTap;
33 :
34 1 : UserFullScreenHelperPage({
35 : Key key,
36 : @required this.helperBoxViewModel,
37 : @required this.titleLabel,
38 : @required this.onPositivButtonTap,
39 : @required this.onNegativButtonTap,
40 : this.headerImageViewModel,
41 : this.positivLabel,
42 : this.negativLabel,
43 1 : }) : assert(helperBoxViewModel != null),
44 1 : assert(titleLabel != null),
45 0 : assert(onPositivButtonTap != null),
46 0 : assert(onNegativButtonTap != null);
47 :
48 : final _mvvmPageBuilder = MVVMPageBuilder<UserFullScreenHelperPresenter,
49 : UserFullScreenHelperModel>();
50 : final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
51 :
52 1 : @override
53 : Widget build(BuildContext context) {
54 2 : return _mvvmPageBuilder.build(
55 1 : key: ValueKey('pal_UserFullScreenHelperPage_Builder'),
56 : context: context,
57 1 : multipleAnimControllerBuilder: (tickerProvider) {
58 1 : return [
59 : // Media
60 1 : AnimationController(
61 : vsync: tickerProvider,
62 1 : duration: Duration(
63 : milliseconds: 1100,
64 : ),
65 : ),
66 : // Title
67 1 : AnimationController(
68 : vsync: tickerProvider,
69 1 : duration: Duration(
70 : milliseconds: 700,
71 : ),
72 : ),
73 : // Feedback
74 1 : AnimationController(
75 : vsync: tickerProvider,
76 1 : duration: Duration(
77 : milliseconds: 700,
78 : ),
79 : ),
80 : ];
81 : },
82 1 : animListener: (context, presenter, model) {
83 1 : if (model.mediaAnimation) {
84 1 : this.playAnimation(
85 : context,
86 1 : model.isReversedAnimations,
87 : 0,
88 1 : presenter.onMediaAnimationEnd,
89 : );
90 : }
91 1 : if (model.titleAnimation) {
92 1 : this.playAnimation(
93 : context,
94 1 : model.isReversedAnimations,
95 : 1,
96 1 : presenter.onTitleAnimationEnd,
97 : );
98 : }
99 1 : if (model.feedbackAnimation) {
100 1 : this.playAnimation(
101 : context,
102 1 : model.isReversedAnimations,
103 : 2,
104 1 : presenter.onFeedbackAnimationEnd,
105 : );
106 : }
107 : },
108 2 : presenterBuilder: (context) => UserFullScreenHelperPresenter(this),
109 2 : builder: (context, presenter, model) => _buildPage(context, presenter, model),
110 : );
111 : }
112 :
113 1 : Widget _buildPage(
114 : final MvvmContext context,
115 : final UserFullScreenHelperPresenter presenter,
116 : final UserFullScreenHelperModel model,
117 : ) {
118 1 : return AnimatedOpacity(
119 1 : duration: Duration(milliseconds: 500),
120 : curve: Curves.fastOutSlowIn,
121 1 : opacity: model?.helperOpacity,
122 1 : child: Scaffold(
123 2 : backgroundColor: helperBoxViewModel?.backgroundColor,
124 1 : key: _scaffoldKey,
125 1 : body: SafeArea(
126 1 : child: Container(
127 1 : key: ValueKey('pal_UserFullScreenHelperPage'),
128 : width: double.infinity,
129 1 : child: Padding(
130 1 : padding: EdgeInsets.symmetric(horizontal: 16, vertical: 30.0),
131 1 : child: Column(
132 : mainAxisAlignment: MainAxisAlignment.center,
133 1 : children: [
134 6 : if (headerImageViewModel?.url != null && headerImageViewModel.url.length > 0)
135 1 : Flexible(
136 1 : key: ValueKey('pal_UserFullScreenHelperPage_Media'),
137 : flex: 3,
138 1 : child: Padding(
139 : padding: const EdgeInsets.symmetric(horizontal: 20.0),
140 1 : child: _buildMedia(context),
141 : ),
142 : ),
143 1 : Flexible(
144 1 : key: ValueKey('pal_UserFullScreenHelperPage_Title'),
145 : flex: 4,
146 1 : child: Padding(
147 : padding: const EdgeInsets.only(top: 40.0),
148 1 : child: _buildTitle(context),
149 : ),
150 : ),
151 1 : Container(
152 1 : key: ValueKey('pal_UserFullScreenHelperPage_Feedback'),
153 1 : child: Padding(
154 : padding: const EdgeInsets.only(top: 30.0),
155 1 : child: _buildFeedback(context, presenter),
156 : ),
157 : ),
158 : ],
159 : ),
160 : ),
161 : ),
162 : ),
163 : ),
164 : );
165 : }
166 :
167 1 : Widget _buildMedia(MvvmContext context) {
168 1 : return AnimatedScaleWidget(
169 1 : widget: ClipRRect(
170 1 : borderRadius: BorderRadius.circular(15.0),
171 1 : child: CachedNetworkImage(
172 2 : imageUrl: headerImageViewModel?.url,
173 : fit: BoxFit.cover,
174 1 : placeholder: (context, url) =>
175 2 : Center(child: CircularProgressIndicator()),
176 0 : errorWidget: (BuildContext context, String url, dynamic error) {
177 0 : return Image.asset(
178 : 'packages/pal/assets/images/create_helper.png');
179 : },
180 : ),
181 : ),
182 2 : animationController: context.animationsControllers[0],
183 : );
184 : }
185 :
186 1 : Widget _buildTitle(MvvmContext context) {
187 1 : return AnimatedTranslateWidget(
188 2 : animationController: context.animationsControllers[1],
189 1 : widget: SingleChildScrollView(
190 1 : child: Text(
191 2 : titleLabel?.text ?? 'Title',
192 : textAlign: TextAlign.center,
193 1 : style: TextStyle(
194 2 : color: titleLabel?.fontColor ?? Colors.white,
195 2 : fontSize: titleLabel?.fontSize ?? 60.0,
196 2 : fontWeight: titleLabel?.fontWeight,
197 4 : ).merge(GoogleFonts.getFont(titleLabel?.fontFamily ?? 'Montserrat')),
198 : ),
199 : ),
200 : );
201 : }
202 :
203 1 : Widget _buildFeedback(
204 : MvvmContext context, UserFullScreenHelperPresenter presenter) {
205 1 : return AnimatedTranslateWidget(
206 4 : position: Tween<Offset>(begin: Offset(0.0, -1.0), end: Offset(0.0, 0.0)),
207 2 : animationController: context.animationsControllers[2],
208 1 : widget: Column(
209 1 : children: [
210 1 : SizedBox(
211 : width: double.infinity,
212 1 : child: RaisedButton(
213 1 : key: ValueKey(
214 : 'pal_UserFullScreenHelperPage_Feedback_PositivButton'),
215 1 : onPressed: () {
216 1 : HapticFeedback.selectionClick();
217 1 : presenter.onPositivButtonCallback();
218 : },
219 : color: Colors.greenAccent,
220 1 : shape: RoundedRectangleBorder(
221 1 : borderRadius: BorderRadius.circular(8.0),
222 : ),
223 1 : child: Padding(
224 : padding: const EdgeInsets.symmetric(vertical: 12.0),
225 1 : child: Text(
226 2 : positivLabel?.text ?? 'Ok, thanks !',
227 1 : style: TextStyle(
228 2 : color: positivLabel?.fontColor ?? Colors.white,
229 2 : fontSize: positivLabel?.fontSize ?? 23.0,
230 2 : fontWeight: positivLabel?.fontWeight ?? FontWeight.bold,
231 2 : ).merge(GoogleFonts.getFont(
232 2 : positivLabel?.fontFamily ?? 'Montserrat')),
233 : ),
234 : ),
235 : ),
236 : ),
237 1 : SizedBox(
238 : height: 10.0,
239 : ),
240 1 : SizedBox(
241 : width: double.infinity,
242 1 : child: RaisedButton(
243 1 : key: ValueKey(
244 : 'pal_UserFullScreenHelperPage_Feedback_NegativButton'),
245 1 : onPressed: () {
246 1 : HapticFeedback.selectionClick();
247 1 : presenter.onNegativButtonCallback();
248 : },
249 : color: Colors.redAccent,
250 1 : shape: RoundedRectangleBorder(
251 1 : borderRadius: BorderRadius.circular(8.0),
252 : ),
253 1 : child: Padding(
254 : padding: const EdgeInsets.symmetric(vertical: 12.0),
255 1 : child: Text(
256 2 : negativLabel?.text ?? 'This is not helping',
257 1 : style: TextStyle(
258 2 : color: negativLabel?.fontColor ?? Colors.white,
259 2 : fontSize: negativLabel?.fontSize ?? 13.0,
260 2 : fontWeight: negativLabel?.fontWeight ?? FontWeight.bold,
261 2 : ).merge(GoogleFonts.getFont(
262 2 : negativLabel?.fontFamily ?? 'Montserrat')),
263 : ),
264 : ),
265 : ),
266 : )
267 : ],
268 : ),
269 : );
270 : }
271 :
272 1 : @override
273 : void onNegativButtonCallback() {
274 2 : this.onNegativButtonTap();
275 : }
276 :
277 1 : @override
278 : void onPositivButtonCallback() {
279 2 : this.onPositivButtonTap();
280 : }
281 :
282 1 : @override
283 : void playAnimation(
284 : MvvmContext context,
285 : bool isReversed,
286 : int index,
287 : Function callback,
288 : ) {
289 : if (isReversed) {
290 2 : context.animationsControllers[index]
291 1 : .reverse()
292 3 : .then((value) => callback());
293 : } else {
294 2 : context.animationsControllers[index]
295 1 : .forward()
296 3 : .then((value) => callback());
297 : }
298 : }
299 : }
|