CWA-216 | applied new design to disclaimer page and faq page

Oleksandr Sobol committed May 22, 2020 at 19:15 UTC 2356cda87918e2d557888735ae5bec35116320b6
2 files changed +332 -261
lib/src/screens/disclaimer/disclaimer_page.dart
+230 -229
@@ -6,6 +6,8 @@ import 'package:cake_wallet/palette.dart';
6 import 'package:url_launcher/url_launcher.dart';
7 import 'package:cake_wallet/src/screens/base_page.dart';
8 import 'package:cake_wallet/src/widgets/primary_button.dart';
9 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
10 +import 'package:cake_wallet/generated/i18n.dart';
11
12 class DisclaimerPage extends BasePage {
13 DisclaimerPage({this.isReadOnly = false});
@@ -13,7 +15,7 @@ class DisclaimerPage extends BasePage {
15 final bool isReadOnly;
16
17 @override
16 - bool get isModalBackButton => false;
18 + Color get backgroundColor => PaletteDark.historyPanel;
19
20 @override
21 String get title => 'Terms of Use';
@@ -34,7 +36,7 @@ class DisclaimerPageBody extends StatefulWidget {
36 class DisclaimerBodyState extends State<DisclaimerPageBody> {
37 DisclaimerBodyState(this._isAccepted);
38
37 - static const xmrtoUrl = 'https://xmr.to/app_static/html/tos.html';
39 + static const xmrtoUrl = 'https://xmr.to/terms-of-service';
40 static const changenowUrl = 'https://changenow.io/terms-of-use';
41 static const morphUrl = 'http://morphtoken.com/terms';
42
@@ -55,22 +57,11 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
57 await showDialog<void>(
58 context: context,
59 builder: (BuildContext context) {
58 - return AlertDialog(
59 - title: Text(
60 - 'Terms and conditions',
61 - textAlign: TextAlign.center,
62 - ),
63 - content: Text(
64 - 'By using this app, you agree to the Terms of Agreement set forth to below',
65 - textAlign: TextAlign.center,
66 - ),
67 - actions: <Widget>[
68 - FlatButton(
69 - onPressed: () {
70 - Navigator.of(context).pop();
71 - },
72 - child: Text('OK')),
73 - ],
60 + return AlertWithOneAction(
61 + alertTitle: 'Terms and conditions',
62 + alertContent: 'By using this app, you agree to the Terms of Agreement set forth to below',
63 + buttonText: S.of(context).ok,
64 + buttonAction: () => Navigator.of(context).pop()
65 );
66 });
67 }
@@ -86,245 +77,255 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
77
78 @override
79 Widget build(BuildContext context) {
89 - return Column(
90 - children: <Widget>[
91 - SizedBox(height: 10.0),
92 - Expanded(
93 - child: Stack(
94 - children: <Widget>[
95 - SingleChildScrollView(
96 - padding: EdgeInsets.only(left: 25.0, right: 25.0),
97 - child: Column(
80 + return Container(
81 + color: PaletteDark.historyPanel,
82 + child: Column(
83 + children: <Widget>[
84 + SizedBox(height: 10.0),
85 + Expanded(
86 + child: Stack(
87 children: <Widget>[
99 - !_isAccepted
100 - ? Row(
88 + SingleChildScrollView(
89 + padding: EdgeInsets.only(left: 24.0, right: 24.0),
90 + child: Column(
91 + children: <Widget>[
92 + !_isAccepted
93 + ? Row(
94 children: <Widget>[
95 Expanded(
96 child: Text(
97 'Terms and conditions',
98 textAlign: TextAlign.center,
99 style: TextStyle(
107 - fontSize: 20.0,
108 - fontWeight: FontWeight.bold),
100 + fontSize: 20.0,
101 + fontWeight: FontWeight.bold,
102 + color: Colors.white
103 + ),
104 ),
105 )
106 ],
107 )
113 - : Offstage(),
114 - !_isAccepted
115 - ? SizedBox(
108 + : Offstage(),
109 + !_isAccepted
110 + ? SizedBox(
111 height: 20.0,
112 )
118 - : Offstage(),
119 - Row(
120 - children: <Widget>[
121 - Expanded(
122 - child: Text(
123 - 'Legal Disclaimer\nAnd\nTerms of Use',
124 - textAlign: TextAlign.center,
125 - style: TextStyle(
126 - fontSize: 12.0, fontWeight: FontWeight.bold),
113 + : Offstage(),
114 + Row(
115 + children: <Widget>[
116 + Expanded(
117 + child: Text(
118 + 'Legal Disclaimer\nAnd\nTerms of Use',
119 + textAlign: TextAlign.center,
120 + style: TextStyle(
121 + fontSize: 12.0,
122 + fontWeight: FontWeight.bold,
123 + color: Colors.white
124 + ),
125 + ),
126 + )
127 + ],
128 ),
128 - )
129 - ],
130 - ),
131 - SizedBox(
132 - height: 16.0,
133 - ),
134 - Row(
135 - children: <Widget>[
136 - Expanded(
137 - child: Text(
138 - _fileText,
139 - style: TextStyle(fontSize: 12.0),
140 - ))
141 - ],
142 - ),
143 - SizedBox(
144 - height: 16.0,
145 - ),
146 - Row(
147 - mainAxisAlignment: MainAxisAlignment.start,
148 - children: <Widget>[
149 - Expanded(
150 - child: Text(
151 - 'Other Terms and Conditions',
152 - textAlign: TextAlign.left,
153 - style: TextStyle(
154 - fontSize: 14.0, fontWeight: FontWeight.bold),
129 + SizedBox(
130 + height: 16.0,
131 ),
156 - )
157 - ],
158 - ),
159 - SizedBox(
160 - height: 16.0,
161 - ),
162 - Row(
163 - mainAxisAlignment: MainAxisAlignment.start,
164 - children: <Widget>[
165 - Expanded(
166 - child: GestureDetector(
167 - onTap: () => launchUrl(xmrtoUrl),
168 - child: Text(
169 - xmrtoUrl,
170 - textAlign: TextAlign.left,
171 - style: TextStyle(
172 - color: Colors.blue,
173 - fontSize: 14.0,
174 - fontWeight: FontWeight.normal,
175 - decoration: TextDecoration.underline),
132 + Row(
133 + children: <Widget>[
134 + Expanded(
135 + child: Text(
136 + _fileText,
137 + style: TextStyle(
138 + fontSize: 12.0,
139 + color: Colors.white
140 + ),
141 + ))
142 + ],
143 ),
177 - ))
178 - ],
179 - ),
180 - SizedBox(
181 - height: 16.0,
182 - ),
183 - Row(
184 - mainAxisAlignment: MainAxisAlignment.start,
185 - children: <Widget>[
186 - Expanded(
187 - child: GestureDetector(
188 - onTap: () => launchUrl(changenowUrl),
189 - child: Text(
190 - changenowUrl,
191 - textAlign: TextAlign.left,
192 - style: TextStyle(
193 - color: Colors.blue,
194 - fontSize: 14.0,
195 - fontWeight: FontWeight.normal,
196 - decoration: TextDecoration.underline),
144 + SizedBox(
145 + height: 16.0,
146 ),
198 - ))
199 - ],
200 - ),
201 - SizedBox(
202 - height: 16.0,
147 + Row(
148 + mainAxisAlignment: MainAxisAlignment.start,
149 + children: <Widget>[
150 + Expanded(
151 + child: Text(
152 + 'Other Terms and Conditions',
153 + textAlign: TextAlign.left,
154 + style: TextStyle(
155 + fontSize: 14.0,
156 + fontWeight: FontWeight.bold,
157 + color: Colors.white
158 + ),
159 + ),
160 + )
161 + ],
162 + ),
163 + SizedBox(
164 + height: 16.0,
165 + ),
166 + Row(
167 + mainAxisAlignment: MainAxisAlignment.start,
168 + children: <Widget>[
169 + Expanded(
170 + child: GestureDetector(
171 + onTap: () => launchUrl(xmrtoUrl),
172 + child: Text(
173 + xmrtoUrl,
174 + textAlign: TextAlign.left,
175 + style: TextStyle(
176 + color: Colors.blue,
177 + fontSize: 14.0,
178 + fontWeight: FontWeight.normal,
179 + decoration: TextDecoration.underline),
180 + ),
181 + ))
182 + ],
183 + ),
184 + SizedBox(
185 + height: 16.0,
186 + ),
187 + Row(
188 + mainAxisAlignment: MainAxisAlignment.start,
189 + children: <Widget>[
190 + Expanded(
191 + child: GestureDetector(
192 + onTap: () => launchUrl(changenowUrl),
193 + child: Text(
194 + changenowUrl,
195 + textAlign: TextAlign.left,
196 + style: TextStyle(
197 + color: Colors.blue,
198 + fontSize: 14.0,
199 + fontWeight: FontWeight.normal,
200 + decoration: TextDecoration.underline),
201 + ),
202 + ))
203 + ],
204 + ),
205 + SizedBox(
206 + height: 16.0,
207 + ),
208 + Row(
209 + mainAxisAlignment: MainAxisAlignment.start,
210 + children: <Widget>[
211 + Expanded(
212 + child: GestureDetector(
213 + onTap: () => launchUrl(morphUrl),
214 + child: Text(
215 + morphUrl,
216 + textAlign: TextAlign.left,
217 + style: TextStyle(
218 + color: Colors.blue,
219 + fontSize: 14.0,
220 + fontWeight: FontWeight.normal,
221 + decoration: TextDecoration.underline),
222 + ),
223 + ))
224 + ],
225 + ),
226 + SizedBox(
227 + height: 16.0,
228 + )
229 + ],
230 + ),
231 ),
204 - Row(
205 - mainAxisAlignment: MainAxisAlignment.start,
206 - children: <Widget>[
207 - Expanded(
208 - child: GestureDetector(
209 - onTap: () => launchUrl(morphUrl),
210 - child: Text(
211 - morphUrl,
212 - textAlign: TextAlign.left,
213 - style: TextStyle(
214 - color: Colors.blue,
215 - fontSize: 14.0,
216 - fontWeight: FontWeight.normal,
217 - decoration: TextDecoration.underline),
232 + Container(
233 + alignment: Alignment.bottomCenter,
234 + child: Container(
235 + height: 12.0,
236 + child: ClipRect(
237 + child: BackdropFilter(
238 + filter: ImageFilter.blur(sigmaX: 0.7, sigmaY: 0.7),
239 + child: Container(
240 + decoration: BoxDecoration(
241 + gradient: LinearGradient(
242 + colors: [
243 + PaletteDark.historyPanel.withOpacity(0.0),
244 + PaletteDark.historyPanel,
245 + ],
246 + begin: FractionalOffset.topCenter,
247 + end: FractionalOffset.bottomCenter,
248 + ),
249 ),
219 - ))
220 - ],
221 - ),
222 - SizedBox(
223 - height: 16.0,
250 + ),
251 + ),
252 + ),
253 + ),
254 )
255 ],
226 - ),
227 - ),
228 - Container(
229 - alignment: Alignment.bottomCenter,
230 - child: Container(
231 - height: 12.0,
232 - child: ClipRect(
233 - child: BackdropFilter(
234 - filter: ImageFilter.blur(sigmaX: 0.7, sigmaY: 0.7),
235 - child: Container(
236 - decoration: BoxDecoration(
237 - gradient: LinearGradient(
238 - colors: [
239 - Theme.of(context).backgroundColor.withOpacity(0.0),
240 - Theme.of(context).backgroundColor,
256 + )),
257 + if (!widget.isReadOnly) ...[
258 + !_isAccepted
259 + ? Row(
260 + children: <Widget>[
261 + Expanded(
262 + child: Container(
263 + padding: EdgeInsets.only(
264 + left: 24.0, top: 10.0, right: 24.0, bottom: 10.0),
265 + child: InkWell(
266 + onTap: () {
267 + setState(() {
268 + _checked = !_checked;
269 + });
270 + },
271 + child: Row(
272 + mainAxisAlignment: MainAxisAlignment.start,
273 + children: <Widget>[
274 + Container(
275 + height: 24.0,
276 + width: 24.0,
277 + margin: EdgeInsets.only(
278 + right: 10.0,
279 + ),
280 + decoration: BoxDecoration(
281 + border: Border.all(
282 + color: Palette.lightGrey, width: 1.0),
283 + borderRadius: BorderRadius.all(
284 + Radius.circular(8.0)),
285 + color: PaletteDark.historyPanel),
286 + child: _checked
287 + ? Icon(
288 + Icons.check,
289 + color: Colors.blue,
290 + size: 20.0,
291 + )
292 + : null,
293 + ),
294 + Text(
295 + 'I agree to Terms of Use',
296 + style: TextStyle(
297 + fontWeight: FontWeight.bold,
298 + fontSize: 14.0,
299 + color: Colors.white
300 + ),
301 + )
302 ],
242 - begin: FractionalOffset.topCenter,
243 - end: FractionalOffset.bottomCenter,
303 ),
245 - ),
246 - ),
247 - ),
304 + )),
305 ),
306 + ],
307 + )
308 + : Offstage(),
309 + !_isAccepted
310 + ? Container(
311 + padding:
312 + EdgeInsets.only(left: 24.0, right: 24.0, bottom: 24.0),
313 + child: PrimaryButton(
314 + onPressed: _checked ? () {} : null,
315 + text: 'Accept',
316 + color: Colors.green,
317 + textColor: Colors.white,
318 ),
319 )
320 + : Offstage(),
321 + _isAccepted
322 + ? SizedBox(
323 + height: 24.0,
324 + )
325 + : Offstage()
326 ],
252 - )),
253 - if (!widget.isReadOnly) ...[
254 - !_isAccepted
255 - ? Row(
256 - children: <Widget>[
257 - Expanded(
258 - child: Container(
259 - padding: EdgeInsets.only(
260 - left: 25.0, top: 10.0, right: 25.0, bottom: 10.0),
261 - child: InkWell(
262 - onTap: () {
263 - setState(() {
264 - _checked = !_checked;
265 - });
266 - },
267 - child: Row(
268 - mainAxisAlignment: MainAxisAlignment.start,
269 - children: <Widget>[
270 - Container(
271 - height: 25.0,
272 - width: 25.0,
273 - margin: EdgeInsets.only(
274 - right: 10.0,
275 - ),
276 - decoration: BoxDecoration(
277 - border: Border.all(
278 - color: Palette.lightGrey, width: 1.0),
279 - borderRadius: BorderRadius.all(
280 - Radius.circular(8.0)),
281 - color: Theme.of(context).backgroundColor),
282 - child: _checked
283 - ? Icon(
284 - Icons.check,
285 - color: Colors.blue,
286 - size: 20.0,
287 - )
288 - : null,
289 - ),
290 - Text(
291 - 'I agree to Terms of Use',
292 - style: TextStyle(
293 - fontWeight: FontWeight.bold,
294 - fontSize: 14.0),
295 - )
296 - ],
297 - ),
298 - )),
299 - ),
300 - ],
301 - )
302 - : Offstage(),
303 - !_isAccepted
304 - ? Container(
305 - padding:
306 - EdgeInsets.only(left: 25.0, right: 25.0, bottom: 25.0),
307 - child: PrimaryButton(
308 - onPressed: _checked ? () {} : null,
309 - text: 'Accept',
310 - color: Theme.of(context)
311 - .primaryTextTheme
312 - .button
313 - .backgroundColor,
314 - textColor: Theme.of(context)
315 - .primaryTextTheme
316 - .button
317 - .color,
318 - ),
319 - )
320 - : Offstage(),
321 - _isAccepted
322 - ? SizedBox(
323 - height: 20.0,
324 - )
325 - : Offstage()
327 ],
327 - ],
328 + ),
329 );
330 }
331 }
lib/src/screens/faq/faq_page.dart
+102 -32
@@ -1,11 +1,11 @@
1 import 'dart:convert';
2 -import 'package:cake_wallet/palette.dart';
2 import 'package:flutter/material.dart';
3 import 'package:flutter/services.dart';
4 import 'package:provider/provider.dart';
5 import 'package:cake_wallet/generated/i18n.dart';
6 import 'package:cake_wallet/src/stores/settings/settings_store.dart';
7 import 'package:cake_wallet/src/screens/base_page.dart';
8 +import 'package:cake_wallet/palette.dart';
9
10 class FaqPage extends BasePage {
11 @override
@@ -15,7 +15,23 @@ class FaqPage extends BasePage {
15 Color get backgroundColor => PaletteDark.historyPanel;
16
17 @override
18 - Widget body(BuildContext context) {
18 + Widget body(BuildContext context) => FaqForm();
19 +}
20 +
21 +class FaqForm extends StatefulWidget {
22 + @override
23 + FaqFormState createState() => FaqFormState();
24 +}
25 +
26 +class FaqFormState extends State<FaqForm> {
27 + final addIcon = Icon(Icons.add, color: Colors.white);
28 + final removeIcon = Icon(Icons.remove, color: Colors.green);
29 + List<Icon> icons;
30 + List<Color> colors;
31 + bool isLoaded = false;
32 +
33 + @override
34 + Widget build(BuildContext context) {
35 return Container(
36 color: PaletteDark.historyPanel,
37 padding: EdgeInsets.only(top: 12),
@@ -25,36 +41,79 @@ class FaqPage extends BasePage {
41 builder: (context, snapshot) {
42 final faqItems = jsonDecode(snapshot.data.toString()) as List;
43
28 - return ListView.separated(
29 - itemBuilder: (BuildContext context, int index) {
30 - final itemTitle = faqItems[index]["question"].toString();
31 - final itemChild = faqItems[index]["answer"].toString();
44 + if (snapshot.hasData) {
45 + setIconsAndColors(faqItems.length);
46 + }
47 +
48 + return SingleChildScrollView(
49 + child: ListView.separated(
50 + shrinkWrap: true,
51 + physics: NeverScrollableScrollPhysics(),
52 + itemBuilder: (BuildContext context, int index) {
53 + final itemTitle = faqItems[index]["question"].toString();
54 + final itemChild = faqItems[index]["answer"].toString();
55
33 - return ExpansionTile(
34 - title: Padding(
35 - padding: EdgeInsets.only(left: 8, top: 12, bottom: 12),
36 - child: Text(itemTitle),
37 - ),
38 - backgroundColor: PaletteDark.menuHeader,
39 - children: <Widget>[
40 - Row(
41 - mainAxisAlignment: MainAxisAlignment.start,
42 - children: <Widget>[
43 - Expanded(
44 - child: Container(
45 - padding: EdgeInsets.only(left: 24.0, right: 24.0, bottom: 4),
46 - child: Text(
47 - itemChild,
48 - ),
49 - ))
50 - ],
51 - )
52 - ],
53 - );
54 - },
55 - separatorBuilder: (_, __) =>
56 - Divider(color: PaletteDark.mainBackgroundColor, height: 1.0),
57 - itemCount: faqItems == null ? 0 : faqItems.length,
56 + return ExpansionTile(
57 + title: Padding(
58 + padding: EdgeInsets.only(left: 8, top: 12, bottom: 12),
59 + child: Text(
60 + itemTitle,
61 + style: TextStyle(
62 + fontSize: 14,
63 + fontWeight: FontWeight.w600,
64 + color: colors[index]
65 + ),
66 + ),
67 + ),
68 + trailing: Padding(
69 + padding: EdgeInsets.only(right: 24),
70 + child: Container(
71 + width: double.minPositive,
72 + child: Center(
73 + child: icons[index]
74 + ),
75 + ),
76 + ),
77 + backgroundColor: PaletteDark.menuHeader,
78 + onExpansionChanged: (value) {
79 + setState(() {
80 + if (value) {
81 + icons[index] = removeIcon;
82 + colors[index] = Colors.green;
83 + } else {
84 + icons[index] = addIcon;
85 + colors[index] = Colors.white;
86 + }
87 + });
88 + },
89 + children: <Widget>[
90 + Row(
91 + mainAxisAlignment: MainAxisAlignment.start,
92 + children: <Widget>[
93 + Expanded(
94 + child: Container(
95 + padding: EdgeInsets.only(
96 + left: 24.0,
97 + right: 24.0,
98 + bottom: 8
99 + ),
100 + child: Text(
101 + itemChild,
102 + style: TextStyle(
103 + fontSize: 12,
104 + color: Colors.white
105 + ),
106 + ),
107 + ))
108 + ],
109 + )
110 + ],
111 + );
112 + },
113 + separatorBuilder: (_, __) =>
114 + Container(color: PaletteDark.mainBackgroundColor, height: 1.0),
115 + itemCount: faqItems == null ? 0 : faqItems.length,
116 + ),
117 );
118 },
119 future: rootBundle.loadString(getFaqPath(context)),
@@ -63,6 +122,17 @@ class FaqPage extends BasePage {
122 );
123 }
124
125 + void setIconsAndColors(int index) {
126 + if (isLoaded) {
127 + return;
128 + }
129 +
130 + icons = List.generate(index, (int i) => addIcon);
131 + colors = List.generate(index, (int i) => Colors.white);
132 +
133 + isLoaded = true;
134 + }
135 +
136 String getFaqPath(BuildContext context) {
137 final settingsStore = Provider.of<SettingsStore>(context);
138
@@ -95,4 +165,4 @@ class FaqPage extends BasePage {
165 return 'assets/faq/faq_en.json';
166 }
167 }
98 -}
168 +}
\ No newline at end of file