YSNetWork.dart 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. import 'dart:convert';
  2. import 'package:dio/dio.dart';
  3. import 'package:flutter/cupertino.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_wallet/tools/YSLoadData.dart';
  6. import 'package:flutter_wallet/tools/YSSqflite.dart';
  7. import 'package:fluttertoast/fluttertoast.dart';
  8. import 'package:shared_preferences/shared_preferences.dart';
  9. import 'YSTools.dart';
  10. import 'package:http/http.dart' as http;
  11. //https://bakewallet.io
  12. //http://8.222.222.151
  13. //https://bakewallet.info
  14. String base = 'https://bakewallet.info/api/v1/';
  15. String base2 = 'https://bakewallet.info/api';
  16. int outTime = 100000;//10000
  17. enum RequestType{
  18. put,
  19. delete,
  20. get,
  21. post
  22. }
  23. class YSNetWork{
  24. static ysRequestHttp(BuildContext context,{required RequestType type,required String api,required dynamic
  25. parameter,bool isLoading = false,bool isToken = true,required ValueSetter successSetter,VoidCallback? errorSetter}) async{
  26. if(isLoading==false){
  27. String url = '$base$api';
  28. if(api=='cross-configs'||api.contains('cross-txs')){
  29. url = 'https://cross.bakewallet.org/api/v1/$api';
  30. }
  31. SharedPreferences prefs = await SharedPreferences.getInstance();
  32. String token = prefs.getString('token')??'';
  33. // LogUtil.d('请求token:$token');
  34. Map<String, dynamic> httpHeaders = {
  35. 'Accept': 'application/json,*/*',
  36. 'Content-Type': 'application/json',
  37. if(isToken==true)'Authorization': 'Bearer $token'
  38. };
  39. LogUtil.d('请求头 $httpHeaders');
  40. try {
  41. LogUtil.d('请求网址:$url\n请求参数:$parameter');
  42. Response response;
  43. if(type==RequestType.put){
  44. response = await Dio().put(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  45. }else if(type==RequestType.post){
  46. response = await Dio().post(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  47. }else if(type==RequestType.delete){
  48. response = await Dio().delete(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  49. }else{
  50. response = await Dio().get(url,queryParameters: Map<String, dynamic>.from(parameter),options: Options(receiveTimeout: outTime,headers: httpHeaders));
  51. }
  52. // LogUtil.d('请求网址:$url\n请求结果:${response.data}');
  53. Map dict = response.data;
  54. LogUtil.d('请求网址:$url\n请求参数:$parameter\n请求结果:$dict');
  55. if(dict['code']==10000){
  56. successSetter(dict);
  57. if(type==RequestType.get){
  58. saveDict(api,dict);
  59. }
  60. }else if(dict['code']==401){
  61. ysFlutterToast('${dict['msg']??''}');
  62. prefs.remove('token');
  63. // ignore: use_build_context_synchronously
  64. // Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context){
  65. // return const YSLogin();
  66. // }), (route) => false);
  67. }else{
  68. ysFlutterToast('${dict['msg']??''}');
  69. }
  70. } catch (error) {
  71. LogUtil.d('请求网址:$url\n请求参数:$parameter\n网络错误$api:$error');
  72. if(type==RequestType.get){
  73. Map loadD = await loadDict(api);
  74. if(loadD.isNotEmpty){
  75. successSetter(loadD);
  76. }else if(api=='chains'){
  77. successSetter(YSLoadData().typeDict);
  78. }
  79. }
  80. if(errorSetter!=null){
  81. errorSetter();
  82. }
  83. }
  84. }else{
  85. ysShowCenterAlertView(context, YSNetWorkView(type: type, api: api,parameter: parameter,isLoading: isLoading,isToken: isToken,imageSetter: (value){},successSetter: (value){
  86. if(value.isEmpty){
  87. if(errorSetter!=null){
  88. errorSetter();
  89. }
  90. }else{
  91. successSetter(value);
  92. }
  93. },),isTrans: true);
  94. }
  95. }
  96. static Future<Map> ysRequestHttpNOSet(BuildContext context,{required RequestType type,required String api,required dynamic
  97. parameter,bool isLoading = false,bool isToken = true}) async{
  98. String url = '$base$api';
  99. if(api=='cross-configs'||api.contains('cross-txs')){
  100. url = 'https://cross.bakewallet.org/api/v1/$api';
  101. }
  102. if(api=='tronsign'||api=='createtransfer'||api=='tronswap'||api=='tron/myres'
  103. ||api=='tron/query/approve'||api=='tron/approve/start'||api=='tron/approve/check'
  104. ||api=='tron/approve/check'||api=='tron/query/swap'||api=='tron/doswap'){
  105. url = '$base2/v2/$api';
  106. }
  107. SharedPreferences prefs = await SharedPreferences.getInstance();
  108. String token = prefs.getString('token')??'';
  109. // LogUtil.d('请求token:$token');
  110. Map<String, dynamic> httpHeaders = {
  111. 'Accept': 'application/json,*/*',
  112. 'Content-Type': 'application/json',
  113. if(isToken==true)'Authorization': 'Bearer $token'
  114. };
  115. LogUtil.d('请求头 $httpHeaders');
  116. try {
  117. LogUtil.d('请求网址:$url\n请求参数:$parameter');
  118. Response response;
  119. if(type==RequestType.put){
  120. response = await Dio().put(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  121. }else if(type==RequestType.post){
  122. response = await Dio().post(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  123. }else if(type==RequestType.delete){
  124. response = await Dio().delete(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  125. }else{
  126. response = await Dio().get(url,queryParameters: Map<String, dynamic>.from(parameter),options: Options(receiveTimeout: outTime,headers: httpHeaders));
  127. }
  128. Map dict = response.data;
  129. LogUtil.d('请求网址:$url\n请求参数:$parameter\n请求结果:$dict');
  130. if(dict['code']==10000){
  131. return dict;
  132. }else if(dict['code']==401){
  133. ysFlutterToast('${dict['msg']??''}');
  134. prefs.remove('token');
  135. // ignore: use_build_context_synchronously
  136. // Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context){
  137. // return const YSLogin();
  138. // }), (route) => false);
  139. return {};
  140. }else{
  141. ysFlutterToast('${dict['msg']??''}');
  142. return {};
  143. }
  144. } catch (error) {
  145. LogUtil.d('请求网址:$url\n请求参数:$parameter\n网络错误$api:$error');
  146. return {};
  147. }
  148. }
  149. static ysRequestHttpNOSet2(BuildContext context,{required RequestType type,required String api,required dynamic
  150. parameter,bool isLoading = false,bool isToken = true}) async{
  151. String url = '$base$api';
  152. if(api=='cross-configs'||api.contains('cross-txs')){
  153. url = 'https://cross.bakewallet.org/api/v1/$api';
  154. }
  155. if(api=='tronsign'||api=='createtransfer'||api=='tronswap'||api=='tron/myres'
  156. ||api=='tron/query/approve'||api=='tron/approve/start'||api=='tron/approve/check'||api=='tron/approve/check'){
  157. url = '$base2/v2/$api';
  158. }
  159. SharedPreferences prefs = await SharedPreferences.getInstance();
  160. String token = prefs.getString('token')??'';
  161. // LogUtil.d('请求token:$token');
  162. Map<String, dynamic> httpHeaders = {
  163. 'Accept': 'application/json,*/*',
  164. 'Content-Type': 'application/json',
  165. if(isToken==true)'Authorization': 'Bearer $token'
  166. };
  167. LogUtil.d('请求头 $httpHeaders');
  168. try {
  169. LogUtil.d('请求网址:$url\n请求参数:$parameter');
  170. Response response;
  171. if(type==RequestType.put){
  172. response = await Dio().put(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  173. }else if(type==RequestType.post){
  174. response = await Dio().post(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  175. }else if(type==RequestType.delete){
  176. response = await Dio().delete(url,data: parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  177. }else{
  178. response = await Dio().get(url,queryParameters: Map<String, dynamic>.from(parameter),options: Options(receiveTimeout: outTime,headers: httpHeaders));
  179. }
  180. Map dict = response.data;
  181. LogUtil.d('请求网址:$url\n请求参数:$parameter\n请求结果:$dict');
  182. if(dict['code']==10000){
  183. if(api=='tron/approve/check'){
  184. Map data = dict['data']??{};
  185. if(data.isNotEmpty){
  186. return dict;
  187. }else{
  188. LogUtil.d('ysRequestHttpNOSet2=========$data');
  189. // ignore: use_build_context_synchronously
  190. return ysRequestHttpNOSet2(context, type: type, api: api, parameter: parameter);
  191. }
  192. }else{
  193. return dict;
  194. }
  195. }else if(dict['code']==401){
  196. ysFlutterToast('${dict['msg']??''}');
  197. prefs.remove('token');
  198. // ignore: use_build_context_synchronously
  199. // Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context){
  200. // return const YSLogin();
  201. // }), (route) => false);
  202. // return {};
  203. }else{
  204. ysFlutterToast('${dict['msg']??''}');
  205. // return {};
  206. }
  207. } catch (error) {
  208. LogUtil.d('请求网址:$url\n请求参数:$parameter\n网络错误$api:$error');
  209. // return {};
  210. }
  211. }
  212. static ysRequestHttp2(BuildContext context,{required RequestType type,required String api,required dynamic parameter,bool isLoading = false,bool isToken = true,required
  213. ValueSetter imageSetter,required ValueSetter successSetter}) {
  214. FocusScope.of(context).unfocus();
  215. ysShowCenterAlertView(context, YSImageUploadView(type: type, api: api,parameter: parameter,isLoading: isLoading,isToken: isToken,imageSetter: (value){
  216. imageSetter(value);
  217. },successSetter: (value){
  218. successSetter(value);
  219. }),isTrans: true);
  220. }
  221. static Future<Map> httpNetwork({required String api,int type = 1,required Map request}) async{
  222. try{
  223. var client = http.Client();
  224. String url = '$base$api';
  225. if(api=='bitconinp2sh'||api=='bithash'){
  226. url = '$base2/v2/$api';
  227. }
  228. var body = jsonEncode(request);
  229. LogUtil.d('请求参数=======\n$url\n$body');
  230. // 发送POST请求
  231. var response = await client.post(
  232. Uri.parse(url),
  233. headers: {'Content-Type': 'application/json'},
  234. body: body,
  235. );
  236. LogUtil.d('请求结果=======\n$url\n${response.body}');
  237. Map dict = jsonDecode(response.body);
  238. LogUtil.d('请求结果=======\n$url\n$dict');
  239. if(dict['code']==10000){
  240. return dict;
  241. }else if(dict['code']==5000002){
  242. ysFlutterToast(dict['message']??'');
  243. }
  244. return {};
  245. }catch(error){
  246. LogUtil.d(error);
  247. return {};
  248. }
  249. }
  250. static Future<Map> httpNetwork2({required String api,int type = 1,required Map request,bool isEncode = false}) async{
  251. try{
  252. var client = http.Client();
  253. String url = '$base$api';
  254. if(api=='bitconinp2sh'||api=='bithash'){
  255. url = '$base2/v2/$api';
  256. }
  257. var body = jsonEncode(request);
  258. LogUtil.d('请求参数=======\n$url\n$body');
  259. // 发送POST请求
  260. var response = await client.get(
  261. Uri.parse(url),
  262. headers: {'Content-Type': 'application/json'},
  263. );
  264. LogUtil.d('请求结果=======\n$url\n${response.body}');
  265. Map dict = jsonDecode(response.body);
  266. LogUtil.d('请求结果=======\n$url\n$dict');
  267. if(dict['code']==10000){
  268. return dict;
  269. }else if(dict['code']==5000002){
  270. ysFlutterToast(dict['message']??'');
  271. }
  272. return {};
  273. }catch(error){
  274. LogUtil.d(error);
  275. return {};
  276. }
  277. }
  278. }
  279. void ysFlutterToast(String msg,{bool isCenter = false}){
  280. Fluttertoast.showToast(
  281. msg: msg,
  282. gravity: isCenter?ToastGravity.CENTER:ToastGravity.BOTTOM,
  283. textColor: Colors.white,
  284. backgroundColor: Colors.black87,
  285. timeInSecForIosWeb: 2,
  286. );
  287. }
  288. class YSNetWorkView extends StatefulWidget {
  289. final ValueSetter<Map> successSetter;
  290. final ValueSetter imageSetter;
  291. final RequestType type;
  292. final String api;
  293. final dynamic parameter;
  294. final bool isLoading;
  295. final bool isToken;
  296. final bool isImage;
  297. const YSNetWorkView({Key? key, required this.type, required this.api, this.parameter, this.isLoading = false, this.isToken = true,
  298. required this.imageSetter,this.isImage = false, required this.successSetter}) : super(key: key);
  299. @override
  300. YSNetWorkViewState createState() => YSNetWorkViewState();
  301. }
  302. class YSNetWorkViewState extends State<YSNetWorkView> {
  303. bool _isError = false;
  304. @override
  305. void initState() {
  306. Future.delayed(const Duration(seconds: 0)).then((value) async{
  307. Map dict = await _getData();
  308. widget.successSetter(dict);
  309. });
  310. super.initState();
  311. }
  312. _getData() async{
  313. String url = '$base${widget.api}';
  314. if(widget.api=='cross-configs'||widget.api=='cross-txs'){
  315. url = 'https://cross.bakewallet.org/api/v1/${widget.api}';
  316. }
  317. SharedPreferences prefs = await SharedPreferences.getInstance();
  318. String token = prefs.getString('token')??'';
  319. Map<String, dynamic> httpHeaders = {
  320. 'Accept': 'application/json,*/*',
  321. 'Content-Type': 'application/json',
  322. if(widget.isToken==true)'Authorization': 'Bearer $token'
  323. };
  324. try {
  325. LogUtil.d('请求网址:$url\n请求参数:${widget.parameter}');
  326. Response response;
  327. if(widget.type==RequestType.put){
  328. response = await Dio().put(url,data: widget.parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  329. }else if(widget.type==RequestType.post){
  330. response = await Dio().post(url,data: widget.parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  331. }else if(widget.type==RequestType.delete){
  332. response = await Dio().delete(url,data: widget.parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  333. }else{
  334. response = await Dio().get(url,queryParameters: Map<String, dynamic>.from(widget.parameter),options: Options(receiveTimeout: outTime,headers: httpHeaders));
  335. }
  336. LogUtil.d('请求网址:$url\n请求结果:${response.data}');
  337. Map dict = response.data;
  338. if(!mounted)return;
  339. Navigator.pop(context);
  340. if(dict['code']==10000){
  341. if(widget.type==RequestType.get){
  342. saveDict(widget.api,dict);
  343. }
  344. return dict;
  345. }else if(dict['code']==401){
  346. ysFlutterToast('${dict['msg']??''}');
  347. if (!mounted) return;
  348. // Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context){
  349. // return const YSLogin();
  350. // }), (route) => false);
  351. prefs.remove('token');
  352. return {};
  353. }else{
  354. ysFlutterToast('${dict['msg']??''}');
  355. return {};
  356. }
  357. } catch (error) {
  358. if (!mounted) return;
  359. Navigator.pop(context);
  360. _isError = true;
  361. setState(() {});
  362. LogUtil.d('请求网址:$url\n网络错误:$error');
  363. if(widget.type==RequestType.get){
  364. Map loadD = await loadDict(widget.api);
  365. if(loadD.isNotEmpty){
  366. return loadD;
  367. }else if(widget.api=='chains'){
  368. return YSLoadData().typeDict;
  369. }
  370. }
  371. return {};
  372. }
  373. }
  374. @override
  375. Widget build(BuildContext context) {
  376. return WillPopScope(
  377. onWillPop: () async{
  378. return false;
  379. },
  380. child: widget.isLoading==false?Container():Center(
  381. child: Container(
  382. height: hsp(150),
  383. width: hsp(150),
  384. decoration: const BoxDecoration(
  385. borderRadius: BorderRadius.all(Radius.circular(5)),
  386. color: Colors.black45,
  387. ),
  388. alignment: Alignment.center,
  389. child: Column(
  390. mainAxisSize: MainAxisSize.min,
  391. children: [
  392. SizedBox(
  393. width: 60,
  394. height: 60,
  395. child: _isError==true?const Icon(
  396. Icons.error_outline,size: 60,color: Colors.redAccent,
  397. ):CupertinoActivityIndicator(
  398. radius: hsp(20),
  399. color: Colors.white,
  400. ),
  401. ),
  402. Container(
  403. margin: EdgeInsets.only(top: hsp(15)),
  404. child: Text(_isError==true?'出错了':'请求中',style: TextStyle(fontSize: zsp(16),color: Colors.white,decoration: TextDecoration.none),),
  405. )
  406. ],
  407. ),
  408. ),
  409. ),
  410. );
  411. }
  412. }
  413. saveDict(String key,Map dict) {
  414. YSSqflite3 sqflite3 = YSSqflite3().init();
  415. if(dict.isNotEmpty){
  416. sqflite3.rawInsert(key, dict);
  417. }
  418. }
  419. loadDict(String key) async{
  420. YSSqflite3 sqflite3 = YSSqflite3().init();
  421. Object object = await sqflite3.rawQuery(key);
  422. LogUtil.d('loadDict========$key===========$object');
  423. return object;
  424. }
  425. class YSImageUploadView extends StatefulWidget {
  426. final ValueSetter successSetter;
  427. final ValueSetter imageSetter;
  428. final RequestType type;
  429. final String api;
  430. final dynamic parameter;
  431. final bool isLoading;
  432. final bool isToken;
  433. const YSImageUploadView({Key? key, required this.type, required this.api, this.parameter, this.isLoading = false, this.isToken = true,
  434. required this.imageSetter, required this.successSetter}) : super(key: key);
  435. @override
  436. YSImageUploadViewState createState() => YSImageUploadViewState();
  437. }
  438. class YSImageUploadViewState extends State<YSImageUploadView> {
  439. double _rota1 = 0.0;
  440. double _rota2 = 0.0;
  441. bool _isError = false;
  442. @override
  443. void initState() {
  444. Future.delayed(const Duration(seconds: 0)).then((value) async{
  445. Map dict = await _getData();
  446. if(dict.isNotEmpty){
  447. widget.successSetter(dict);
  448. }
  449. });
  450. super.initState();
  451. }
  452. _getData() async{
  453. String url = '$base${widget.api}';
  454. SharedPreferences prefs = await SharedPreferences.getInstance();
  455. String token = prefs.getString('token')??'';
  456. Map<String, dynamic> httpHeaders = {
  457. 'Accept': 'application/json,*/*',
  458. 'Content-Type': 'application/json',
  459. if(widget.isToken==true)'Authorization': 'Bearer $token'
  460. };
  461. try {
  462. LogUtil.d('请求网址:$url\n请求参数:${widget.parameter}');
  463. // LogUtil.d('请求网址:$url\n加密参数:$secret');
  464. Response response;
  465. if(widget.type==RequestType.put){
  466. response = await Dio().put(url,data: widget.parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  467. }else if(widget.type==RequestType.post){
  468. response = await Dio().post(url,data: widget.parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders),
  469. onReceiveProgress: (int1,int2){
  470. if(int2==-1){
  471. _rota1 = 1;
  472. }else{
  473. _rota1 = int1/int2;
  474. }
  475. setState(() {});
  476. },
  477. onSendProgress: (int1,int2){
  478. _rota2 = int1/int2;
  479. setState(() {});
  480. widget.imageSetter(_rota2);
  481. });
  482. }else if(widget.type==RequestType.delete){
  483. response = await Dio().delete(url,data: widget.parameter,options: Options(receiveTimeout: outTime,headers: httpHeaders));
  484. }else{
  485. response = await Dio().get(url,queryParameters: Map<String, dynamic>.from(widget.parameter),options: Options(receiveTimeout: outTime,headers: httpHeaders));
  486. }
  487. LogUtil.d('请求网址:$url\n请求结果:${response.data}');
  488. // return;
  489. Map dict = response.data;
  490. if(!mounted)return;
  491. Navigator.pop(context);
  492. if(dict['code']==200){
  493. return dict;
  494. }else if(dict['code']==401){
  495. ysFlutterToast('${dict['msg']??''}');
  496. if (!mounted) return;
  497. // Navigator.of(context).push(
  498. // CupertinoPageRoute(builder: (context){
  499. // return const YSLogin();
  500. // })
  501. // );
  502. prefs.remove('token');
  503. return {};
  504. }else{
  505. ysFlutterToast('${dict['msg']??''}');
  506. return {};
  507. }
  508. } catch (error) {
  509. if (!mounted) return;
  510. Navigator.pop(context);
  511. _isError = true;
  512. setState(() {});
  513. LogUtil.d('请求网址:$url\n网络错误:$error');
  514. return {};
  515. }
  516. }
  517. @override
  518. Widget build(BuildContext context) {
  519. return WillPopScope(
  520. onWillPop: () async{
  521. return false;
  522. },
  523. child: widget.isLoading==false?Container():Center(
  524. child: Container(
  525. height: hsp(150),
  526. width: hsp(150),
  527. decoration: const BoxDecoration(
  528. borderRadius: BorderRadius.all(Radius.circular(5)),
  529. color: Colors.black45,
  530. ),
  531. alignment: Alignment.center,
  532. child: Column(
  533. mainAxisSize: MainAxisSize.min,
  534. children: [
  535. SizedBox(
  536. width: 60,
  537. height: 60,
  538. child: _isError==true?const Icon(
  539. Icons.error_outline,size: 60,color: Colors.redAccent,
  540. ):_rota2==1&&_rota1==1?const Icon(
  541. Icons.check,size: 60,color: Colors.green,
  542. ):CircularProgressIndicator(
  543. value: _rota2==1?_rota1:_rota2,
  544. color: Colors.lightBlueAccent,
  545. backgroundColor: Colors.white,
  546. strokeWidth: 5,
  547. ),
  548. ),
  549. Container(
  550. margin: EdgeInsets.only(top: hsp(15)),
  551. child: Text(_isError==true?'出错了':_rota2<1?'上传中':_rota1<1?'接收中':'完成',style: TextStyle(fontSize: zsp(16),color: Colors.white,decoration: TextDecoration.none),),
  552. )
  553. ],
  554. ),
  555. ),
  556. )
  557. );
  558. }
  559. }