menu_home.dart 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  1. import 'package:auto_route/auto_route.dart';
  2. import 'package:cached_network_image/cached_network_image.dart';
  3. import 'package:carousel_slider/carousel_slider.dart';
  4. import 'package:drag_and_drop_lists/drag_and_drop_lists.dart';
  5. import 'package:easy_localization/easy_localization.dart';
  6. import 'package:firebase_messaging/firebase_messaging.dart';
  7. import 'package:flutter/material.dart';
  8. import 'package:flutter_cache_manager/flutter_cache_manager.dart';
  9. import 'package:flutter_linkify/flutter_linkify.dart';
  10. import 'package:provider/provider.dart';
  11. import 'package:telnow_mobile_new/src/api/api_auth_provider.dart';
  12. import 'package:telnow_mobile_new/src/injector/injector.dart';
  13. import 'package:telnow_mobile_new/src/layouts/functions/home.dart';
  14. import 'package:telnow_mobile_new/src/layouts/components/template.dart';
  15. import 'package:telnow_mobile_new/src/layouts/web/banner_detail.dart';
  16. import 'package:telnow_mobile_new/src/layouts/web/message_list.dart';
  17. import 'package:telnow_mobile_new/src/layouts/web/request_create.dart';
  18. import 'package:telnow_mobile_new/src/layouts/web/request_select.dart';
  19. import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
  20. import 'package:telnow_mobile_new/src/utils/U.dart';
  21. import 'package:telnow_mobile_new/src/utils/cache_manager.dart';
  22. import 'package:telnow_mobile_new/src/utils/provider.dart';
  23. import 'package:url_launcher/url_launcher.dart';
  24. import '../../utils/C.dart';
  25. class WebHomePage extends StatefulWidget {
  26. const WebHomePage({super.key});
  27. @override
  28. State<WebHomePage> createState() => _WebHomePageState();
  29. }
  30. class _WebHomePageState extends State<WebHomePage> {
  31. final HomeFunction homeFunc = HomeFunction();
  32. final SharedPreferencesManager sharedPreferencesManager = locator<SharedPreferencesManager>();
  33. @override
  34. void initState() {
  35. Provider.of<ServiceModule>(context, listen: false).reset();
  36. Provider.of<UserModule>(context, listen: false).reset();
  37. WidgetsBinding.instance.addPostFrameCallback((_) {
  38. Future.delayed(Duration(seconds: 1), (){
  39. homeFunc.getProfileData(context);
  40. });
  41. FirebaseMessaging.onMessage.listen((event) {
  42. if(event.data['type'] == 'MESSAGE'){
  43. homeFunc.getUnreadMessages(context);
  44. }
  45. });
  46. });
  47. checkCompatibility();
  48. // TODO: implement initState
  49. super.initState();
  50. }
  51. bool _timeLimit = false;
  52. checkCompatibility() async{
  53. var isCompatible = await U.isCompatibleWith(VersionKey.multiBahasa);
  54. if(isCompatible) {
  55. homeFunc.getContactCenter(context);
  56. }
  57. }
  58. @override
  59. Widget build(BuildContext context) {
  60. return Provider.of<UserModule>(context).user().isNotEmpty?Scaffold(
  61. backgroundColor: backgroundColor,
  62. appBar: PreferredSize(preferredSize: Size.fromHeight(0), child: AppBar(elevation: 0, backgroundColor: primaryColor)),
  63. body: Column(
  64. children: [
  65. Container(
  66. width: double.infinity, color: primaryColor,
  67. padding: EdgeInsets.symmetric(vertical: 20, horizontal: 60),
  68. child: Row(
  69. crossAxisAlignment: CrossAxisAlignment.start,
  70. children: [
  71. Image.asset('assets/image/logo/logo.png', height: 35),
  72. SizedBox(width: 60),
  73. Expanded(
  74. child: Column(
  75. crossAxisAlignment: CrossAxisAlignment.start,
  76. children: [
  77. Row(
  78. children: [
  79. Expanded(
  80. child: GestureDetector(
  81. child: Container(
  82. padding: EdgeInsets.symmetric(vertical: 8, horizontal: 15),
  83. decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
  84. child: Row(
  85. children: [
  86. U.iconsax('search-normal-1', color: textColor),
  87. SizedBox(width: 13),
  88. Expanded(child: Text(Provider.of<UserModule>(context).profile()['searchText'][context.locale.toString()] ?? 'searchAsk'.tr(), style: TextStyle(color: textColor.withValues(alpha: 0.5), fontSize: 14), overflow: TextOverflow.ellipsis))
  89. ],
  90. ),
  91. ),
  92. onTap: () => navigateTo(context, WebReqSelectPage(user: Provider.of<UserModule>(context, listen: false).user(), title: 'search'.tr(), scope: Provider.of<ServiceModule>(context, listen: false).scoopeValue(), placeholder: Provider.of<UserModule>(context, listen: false).profile()['searchText'][context.locale.toString()] != null ? Provider.of<UserModule>(context, listen: false).profile()['searchText'][context.locale.toString()] : 'searchAsk'.tr())).then((val){
  93. val = val??true;
  94. if(val) homeFunc.getFrequentlyRequested(context);
  95. }),
  96. ),
  97. ),
  98. SizedBox(width: 30),
  99. FutureBuilder(future: U.isCompatibleWith(VersionKey.multiBahasa), builder: (context, snapshot){
  100. if(!snapshot.hasData){
  101. return SizedBox();
  102. }
  103. final isCompatible = snapshot.data!;
  104. final hasContactCenter = Provider.of<ServiceModule>(context, listen: false)
  105. .contactCenter()
  106. .toString()
  107. .isNotEmpty;
  108. if (isCompatible && hasContactCenter) {
  109. return Container(
  110. padding: EdgeInsets.all(8),
  111. decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
  112. child: GestureDetector(
  113. onTap: () => launchUrl(Uri.parse(Provider.of<ServiceModule>(context, listen: false).contactCenter().toString())),
  114. child: U.iconsax('phone-number', color: primaryColor, size: 26.0)
  115. ),
  116. ); // replace with the widget you want to show
  117. } else {
  118. return SizedBox(); // or nothing
  119. }
  120. }),
  121. // U.isCompatibleWith(VersionKey.multiBahasa) && Provider.of<ServiceModule>(context, listen: false).contactCenter().toString() != '' ? Container(
  122. // padding: EdgeInsets.all(8),
  123. // decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
  124. // child: GestureDetector(
  125. // onTap: () => launchUrl(Uri.parse(Provider.of<ServiceModule>(context, listen: false).contactCenter().toString())),
  126. // child: U.iconsax('phone-number', color: primaryColor, size: 26.0)
  127. // ),
  128. // ):SizedBox(),
  129. SizedBox(width: 10),
  130. GestureDetector(
  131. child: Container(
  132. padding: EdgeInsets.all(8),
  133. decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
  134. child: Stack(
  135. alignment: Alignment.topRight,
  136. children: [
  137. U.iconsax('sms-notification', color: primaryColor),
  138. Provider.of<ServiceModule>(context).unreadMessage() ? Container(
  139. width: 9, height: 9, margin: EdgeInsets.only(top: 1.3),
  140. decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.all(Radius.circular(50))),
  141. ):Container()
  142. ],
  143. ),
  144. ),
  145. onTap: ()=>navigateTo(context, WebMessageListPage(Provider.of<UserModule>(context, listen: false).user())).then((_){
  146. homeFunc.getUnreadMessages(context);
  147. }),
  148. ),
  149. SizedBox(width: 10),
  150. GestureDetector(
  151. child: Container(
  152. padding: EdgeInsets.all(8),
  153. decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
  154. child: U.iconsax('archive-2', color: primaryColor),
  155. ),
  156. onTap: (){
  157. var pid = U.getPidFromUrl(context.router.currentUrl);
  158. context.router.removeLast();
  159. context.navigateToPath("/app/$pid/menu/history");
  160. },
  161. ),
  162. SizedBox(width: 10),
  163. GestureDetector(
  164. child: Container(
  165. padding: EdgeInsets.all(8),
  166. decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
  167. child: U.iconsax('personalcard', color: primaryColor),
  168. ),
  169. onTap: (){
  170. var pid = U.getPidFromUrl(context.router.currentUrl);
  171. context.router.removeLast();
  172. context.navigateToPath("/app/$pid/menu/account");
  173. },
  174. )
  175. ],
  176. ),
  177. Provider.of<UserModule>(context).profile()['greeting'][context.locale.toString()] != null ? Padding(
  178. padding: EdgeInsets.fromLTRB(15, 5, 15, 0),
  179. child: Text(Provider.of<UserModule>(context).profile()['greeting'][context.locale.toString()], style: TextStyle(color: Colors.white, fontSize: 14), overflow: TextOverflow.ellipsis),
  180. ) : Container(),
  181. ],
  182. ),
  183. ),
  184. SizedBox(width: 60),
  185. Column(
  186. crossAxisAlignment: CrossAxisAlignment.end,
  187. children: [
  188. Text('${Provider.of<UserModule>(context).user()['name']}${(Provider.of<UserModule>(context).user()['guestName']!=null&&Provider.of<UserModule>(context).user()['guestName']!=''?' - ${Provider.of<UserModule>(context).user()['guestName']}':'')}', style: TextStyle(color: Colors.white, fontSize: 18), overflow: TextOverflow.ellipsis),
  189. SizedBox(height: 10),
  190. Container(
  191. child: Row(
  192. children: [
  193. GestureDetector(child: Icon(Icons.info_outline, color: Colors.white, size: 20), onTap: () => showSuccess(context, "scopeDesc".tr()),),
  194. SizedBox(width: 8),
  195. Text('scope'.tr(), style: TextStyle(color: Colors.white, fontSize: 14)),
  196. SizedBox(width: 16),
  197. GestureDetector(
  198. child: Container(
  199. padding: EdgeInsets.fromLTRB(16, 4, 16, 4),
  200. decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(50))),
  201. child: Row(
  202. children: [
  203. Text(Provider.of<ServiceModule>(context).scoopeName(), style: TextStyle(color: primaryColor, fontSize: 14)),
  204. SizedBox(width: 8),
  205. U.iconsax('arrow-down-1', color: primaryColor, size: 14),
  206. ],
  207. ),
  208. ),
  209. onTap: (){
  210. if(Provider.of<ServiceModule>(context, listen: false).scoope().isNotEmpty){
  211. showDialog(
  212. context: context,
  213. builder: (contexts) {
  214. return AlertDialog(
  215. contentPadding: EdgeInsets.symmetric(vertical: 0, horizontal: 10),
  216. content: Column(
  217. mainAxisSize: MainAxisSize.min,
  218. children: [
  219. Container(
  220. margin: EdgeInsets.symmetric(vertical: 16),
  221. child: Text('changeScope'.tr(), style: TextStyle(color: textColor, fontSize: 14), textAlign: TextAlign.center),
  222. ),
  223. divider(),
  224. SizedBox(height: 16),
  225. Column(
  226. children: List.generate(Provider.of<ServiceModule>(context).getScoopeLength(), (i){
  227. return GestureDetector(
  228. child: Container(
  229. color: Colors.white,
  230. padding: EdgeInsets.symmetric(vertical: 16, horizontal: 16),
  231. child: Row(
  232. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  233. children: [
  234. Text(Provider.of<ServiceModule>(context).scoope()[i]['value'], style: TextStyle(color: textColor, fontSize: 14)),
  235. Icon(Provider.of<ServiceModule>(context).checkScoope(Provider.of<ServiceModule>(context).scoope()[i]['key'])?Icons.radio_button_checked:Icons.radio_button_off, color: Provider.of<ServiceModule>(context).checkScoope(Provider.of<ServiceModule>(context).scoope()[i]['key'])?primaryColor:Colors.black45, size: 22),
  236. ],
  237. ),
  238. ),
  239. onTap: () async{
  240. await sharedPreferencesManager.putString(SharedPreferencesManager.keyScoope, Provider.of<ServiceModule>(context, listen: false).scoope()[i]['key']);
  241. Provider.of<ServiceModule>(context, listen: false).setScoopeValue(Provider.of<ServiceModule>(context, listen: false).scoope()[i]['key']);
  242. Provider.of<ServiceModule>(context, listen: false).setScoopeName(Provider.of<ServiceModule>(context, listen: false).scoope()[i]['value']);
  243. Navigator.of(contexts).pop();
  244. var profile = Provider.of<UserModule>(context, listen: false).profile();
  245. if(profile['topMenu']['show'] != null && profile['topMenu']['show'] == true) {
  246. if(U.newServerVersion(1709864293)){
  247. homeFunc.getTopMenuNew(context);
  248. }
  249. else{
  250. homeFunc.getTopMenu(context);
  251. homeFunc.getReqGroup(context);
  252. }
  253. }
  254. if(profile['specialOffer'] != null && profile['specialOffer']['show'] == true) homeFunc.getSpecialOffer(context);
  255. if(profile['frequentlyRequested'] != null && profile['frequentlyRequested']['show'] == true) homeFunc.getFrequentlyRequested(context);
  256. if(profile['banner'] != null && profile['banner']['show'] == true) homeFunc.getBanner(context);
  257. if(profile['quickAction'] != null && profile['quickAction']['show'] == true) homeFunc.getQuickAction(context);
  258. }
  259. );
  260. }),
  261. ),
  262. SizedBox(height: 16),
  263. ],
  264. ),
  265. );
  266. },
  267. );
  268. }
  269. },
  270. )
  271. ],
  272. ),
  273. ),
  274. ],
  275. )
  276. ],
  277. ),
  278. ),
  279. Expanded(
  280. child: Center(
  281. child: Container(
  282. alignment: Alignment.topCenter,
  283. child: SingleChildScrollView(
  284. padding: EdgeInsets.symmetric(vertical: 25, horizontal: 100),
  285. child: Column(
  286. children: [
  287. Provider.of<UserModule>(context).profile()['banner'] != null && Provider.of<UserModule>(context).profile()['banner']['show'] == true ? Container(
  288. child: Provider.of<ServiceModule>(context).banner().isNotEmpty ? LayoutBuilder(
  289. builder: (context, constraints) => CarouselSlider.builder(
  290. itemCount: Provider.of<ServiceModule>(context).banner().length,
  291. options: CarouselOptions(
  292. height: constraints.maxWidth/3.2,
  293. initialPage: 0,
  294. viewportFraction: 1,
  295. autoPlay: true,
  296. autoPlayInterval: Duration(seconds: 5),
  297. autoPlayAnimationDuration: Duration(seconds: 1),
  298. autoPlayCurve: Curves.fastOutSlowIn,
  299. enlargeCenterPage: true,
  300. enableInfiniteScroll: true,
  301. scrollDirection: Axis.horizontal,
  302. ),
  303. itemBuilder: (BuildContext context, int i, int pageViewIndex) => GestureDetector(
  304. child: Container(
  305. width: double.infinity,
  306. decoration: BoxDecoration(
  307. color: Colors.white,
  308. border: Border.all(color: textColor.withValues(alpha: 0.15)),
  309. borderRadius: BorderRadius.all(Radius.circular(12))
  310. ),
  311. child: Column(
  312. crossAxisAlignment: CrossAxisAlignment.start,
  313. children: [
  314. Expanded(
  315. child: Container(
  316. width: double.infinity, height: double.infinity,
  317. child: Provider.of<ServiceModule>(context).banner()[i]['image'] != null ? null : Center(child: Text("noImage".tr(), style: TextStyle(fontStyle: FontStyle.italic, color: Colors.black38), textAlign: TextAlign.center)),
  318. decoration: BoxDecoration(
  319. color: textColor.withValues(alpha: 0.1),
  320. borderRadius: BorderRadius.all(Radius.circular(12)),
  321. image: Provider.of<ServiceModule>(context).banner()[i]['image'] != null ? DecorationImage(
  322. image: CachedNetworkImageProvider(Provider.of<ServiceModule>(context).banner()[i]['image']+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(Provider.of<ServiceModule>(context).banner()[i]['image']))),
  323. fit: BoxFit.cover,
  324. ):null,
  325. ),
  326. ),
  327. ),
  328. Container(
  329. padding: EdgeInsets.all(12),
  330. child: Column(
  331. crossAxisAlignment: CrossAxisAlignment.start,
  332. children: [
  333. Text(Provider.of<ServiceModule>(context).banner()[i][U.langColumn(context, 'title')] != null && Provider.of<ServiceModule>(context).banner()[i][U.langColumn(context, 'title')] != '' ? Provider.of<ServiceModule>(context).banner()[i][U.langColumn(context, 'title')]:Provider.of<ServiceModule>(context).banner()[i]['titleEn']!=null?Provider.of<ServiceModule>(context).banner()[i]['titleEn']:Provider.of<ServiceModule>(context).banner()[i]['title'], style: TextStyle(color: textColor, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
  334. SizedBox(height: 5),
  335. Linkify(
  336. text: Provider.of<ServiceModule>(context).banner()[i][U.langColumn(context, 'description')] != null && Provider.of<ServiceModule>(context).banner()[i][U.langColumn(context, 'description')] != '' ? Provider.of<ServiceModule>(context).banner()[i][U.langColumn(context, 'description')]:Provider.of<ServiceModule>(context).banner()[i]['descriptionEn']!=null?Provider.of<ServiceModule>(context).banner()[i]['descriptionEn']:Provider.of<ServiceModule>(context).banner()[i]['description'], style: TextStyle(color: textColor, fontSize: 14), maxLines: 2, overflow: TextOverflow.ellipsis,
  337. onOpen: (link) async {
  338. if (await canLaunchUrl(Uri.parse(link.url))) {
  339. await launchUrl(Uri.parse(link.url));
  340. }
  341. },
  342. )
  343. ],
  344. ),
  345. ),
  346. Padding(
  347. padding: const EdgeInsets.fromLTRB(12.0, 8.0, 8.0, 8.0),
  348. child: Row(
  349. mainAxisAlignment: MainAxisAlignment.center,
  350. children: List.generate(Provider.of<ServiceModule>(context).banner().length, (index) => Padding(
  351. padding: const EdgeInsets.only(right: 8.0),
  352. child: Container(
  353. width: index == i ? 16.0 : 8.0,
  354. height: 8.0,
  355. decoration: BoxDecoration(borderRadius: BorderRadius.all(Radius.circular(8)), color: primaryColor.withValues(alpha: index == i ? 1 : 0.3)),
  356. ),
  357. ))
  358. ),
  359. )
  360. ],
  361. ),
  362. ),
  363. onTap: ()=>navigateTo(context, WebBannerDetailPage(user: Provider.of<UserModule>(context, listen: false).user(), data: Provider.of<ServiceModule>(context, listen: false).banner()[i])).then((val){
  364. val = val??true;
  365. if(val) homeFunc.getFrequentlyRequested(context);
  366. }),
  367. ),
  368. ),
  369. ) : Container(),
  370. ):Container(),
  371. Provider.of<UserModule>(context).profile()['topMenu']['show'] != null && Provider.of<UserModule>(context).profile()['topMenu']['show'] == true ? Container(
  372. margin: EdgeInsets.only(top: 25, bottom: 25),
  373. padding: EdgeInsets.only(top: 20, bottom: 10),
  374. decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
  375. child: Column(
  376. children: [
  377. LayoutBuilder(
  378. builder: (context, constraints) {
  379. double size = constraints.maxWidth/10;
  380. double minHeight = 135;
  381. return Row(
  382. children: [
  383. Provider.of<ServiceModule>(context).topMenu() != null ? Row(
  384. children: List.generate(Provider.of<ServiceModule>(context).topMenu()!.length+1, (i) {
  385. bool hideOther = i == Provider.of<ServiceModule>(context).topMenu()!.length && U.servantDisplay() && Provider.of<ServiceModule>(context).reqGroup()!.length == 0;
  386. return ConstrainedBox(
  387. constraints: BoxConstraints(minHeight: minHeight),
  388. child: Container(
  389. width: size, height: size,
  390. alignment: Alignment.center,
  391. child: GestureDetector(
  392. child: Column(
  393. mainAxisSize: MainAxisSize.min,
  394. mainAxisAlignment: MainAxisAlignment.start,
  395. children: [
  396. hideOther ? Container(width: size/1.8) : i == Provider.of<ServiceModule>(context).topMenu()!.length ? Container(
  397. child: Container(
  398. padding: EdgeInsets.all(5),
  399. child: SizedBox(width: size/1.8, height: size/1.8, child: U.iconsax('category', color: Color(0xff564F4F), size: 34)),
  400. decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20)), boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 3, offset: Offset(0, 1))]),
  401. ),
  402. ) : Container(
  403. padding: EdgeInsets.all(5),
  404. child: Image(image: CachedNetworkImageProvider(Provider.of<ServiceModule>(context).topMenu()![i]['iconUrl']+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(Provider.of<ServiceModule>(context).topMenu()![i]['iconUrl']+'?bridge-cache=true'))), width: size/1.8, height: size/1.8),
  405. decoration: BoxDecoration(
  406. color: Colors.white,
  407. borderRadius: BorderRadius.all(Radius.circular(20)),
  408. border: Border.all(width: 0.2, color: Colors.black12),
  409. boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 2, offset: Offset(0, 2))]
  410. ),
  411. ),
  412. SizedBox(height: hideOther ? 0:8),
  413. Expanded(
  414. child: hideOther ? Container(width: 70) : SizedBox(width: 70, child: Text(i == Provider.of<ServiceModule>(context).topMenu()!.length ? Provider.of<ServiceModule>(context).expand() ? 'showLess'.tr() : 'more'.tr() : U.servantDisplay() ? Provider.of<ServiceModule>(context).topMenu()![i]['description'] : Provider.of<ServiceModule>(context).topMenu()![i][U.langColumn(context, 'description')]??'', style: TextStyle(color: textColor, fontSize: 12, fontWeight: FontWeight.w300), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center)),
  415. )
  416. ],
  417. ),
  418. onTap: (){
  419. if(i == Provider.of<ServiceModule>(context, listen: false).topMenu()!.length){
  420. if(!hideOther){
  421. Provider.of<ServiceModule>(context, listen: false).setExpand(!Provider.of<ServiceModule>(context, listen: false).expand());
  422. }
  423. }
  424. else{
  425. navigateTo(context, WebReqSelectPage(user: Provider.of<UserModule>(context, listen: false).user(), title: U.servantDisplay() ? Provider.of<ServiceModule>(context, listen: false).topMenu()![i]['description'] : Provider.of<ServiceModule>(context, listen: false).topMenu()![i][U.langColumn(context, 'description')]??'', scope: Provider.of<ServiceModule>(context, listen: false).scoopeValue(), groupCode: Provider.of<ServiceModule>(context, listen: false).topMenu()![i]['code'])).then((val){
  426. val = val??true;
  427. if(val) homeFunc.getFrequentlyRequested(context);
  428. });
  429. }
  430. },
  431. ),
  432. ),
  433. );
  434. }),
  435. ) : Container(),
  436. Provider.of<UserModule>(context).user()['checkedIn'] && Provider.of<UserModule>(context).houseKeeping() && Provider.of<UserModule>(context).dndStatus() ? GestureDetector(
  437. child: Container(
  438. width: size*2, padding: EdgeInsets.symmetric(horizontal: 25),
  439. child: Container(
  440. padding: EdgeInsets.all(10),
  441. child: Column(
  442. children: [
  443. Icon(Icons.remove_circle, color: Color(0xffD81010), size: 18),
  444. SizedBox(height: 10),
  445. Text('info_dnd'.tr(), style: TextStyle(color: textColor, fontSize: 14))
  446. ],
  447. ),
  448. decoration: BoxDecoration(color: Color(0xffD81010).withValues(alpha: 0.15), borderRadius: BorderRadius.all(Radius.circular(10)), border: Border.all(color: Color(0xffD81010))),
  449. ),
  450. decoration: BoxDecoration(border: Border(left: BorderSide(color: Colors.grey))),
  451. ),
  452. onTap: (){
  453. showDialog(
  454. context: context,
  455. builder: (context) => AlertDialog(
  456. content: Text('msg_dnd'.tr(), style: TextStyle(fontSize: 14, color: textColor), textAlign: TextAlign.center),
  457. ),
  458. );
  459. }
  460. ) : Container()
  461. ],
  462. );
  463. },
  464. ),
  465. Provider.of<ServiceModule>(context).expand() ? Column(
  466. children: [
  467. Padding(padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15), child: divider()),
  468. Align(
  469. alignment: Alignment.centerRight,
  470. child: GestureDetector(
  471. child: Container(
  472. padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
  473. margin: EdgeInsets.only(right: 30),
  474. child: Text('customize'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
  475. decoration: BoxDecoration(
  476. color: primaryColor.withValues(alpha: 0.1),
  477. borderRadius: BorderRadius.all(Radius.circular(50))
  478. ),
  479. ),
  480. onTap: ()=>navigateTo(context, WebMenuEditorPage(scope: Provider.of<ServiceModule>(context, listen: false).scoopeValue())),
  481. ),
  482. ),
  483. SizedBox(height: 20),
  484. LayoutBuilder(
  485. builder: (context, constraints) {
  486. double size = constraints.maxWidth/10;
  487. double minHeight = 125;
  488. return Provider.of<ServiceModule>(context).reqGroup() != null ? Wrap(
  489. children: List.generate(Provider.of<ServiceModule>(context).reqGroup()!.length, (i) {
  490. return ConstrainedBox(
  491. constraints: BoxConstraints(minHeight: minHeight),
  492. child: Container(
  493. width: size, height: size,
  494. alignment: Alignment.center,
  495. child: GestureDetector(
  496. child: Column(
  497. mainAxisSize: MainAxisSize.min,
  498. mainAxisAlignment: MainAxisAlignment.start,
  499. children: [
  500. Container(
  501. padding: EdgeInsets.all(5),
  502. child: Image(image: CachedNetworkImageProvider(Provider.of<ServiceModule>(context).reqGroup()![i]['iconUrl']+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(Provider.of<ServiceModule>(context).reqGroup()![i]['iconUrl']+'?bridge-cache=true'))), width: size/1.8, height: size/1.8),
  503. decoration: BoxDecoration(
  504. color: Colors.white,
  505. borderRadius: BorderRadius.all(Radius.circular(20)),
  506. border: Border.all(width: 0.2, color: Colors.black12),
  507. boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 2, offset: Offset(0, 2))]
  508. ),
  509. ),
  510. SizedBox(height: 8),
  511. Expanded(
  512. child: SizedBox(width: 70, child: Text(U.servantDisplay() ? Provider.of<ServiceModule>(context).reqGroup()![i]['description'] : Provider.of<ServiceModule>(context).reqGroup()![i][U.langColumn(context, 'description')]??'', style: TextStyle(color: textColor, fontSize: 12, fontWeight: FontWeight.w300), maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center))
  513. )
  514. ],
  515. ),
  516. onTap: (){
  517. navigateTo(context, WebReqSelectPage(user: Provider.of<UserModule>(context, listen: false).user(), title: U.servantDisplay() ? Provider.of<ServiceModule>(context, listen: false).reqGroup()![i]['description'] : Provider.of<ServiceModule>(context, listen: false).reqGroup()![i][U.langColumn(context, 'description')]??'', scope: Provider.of<ServiceModule>(context, listen: false).scoopeValue(), groupCode: Provider.of<ServiceModule>(context, listen: false).reqGroup()![i]['code'])).then((val){
  518. val = val??true;
  519. if(val) homeFunc.getFrequentlyRequested(context);
  520. });
  521. },
  522. ),
  523. ),
  524. );
  525. }),
  526. ) : Container();
  527. },
  528. )
  529. ],
  530. ) : Container(),
  531. ],
  532. ),
  533. ) : Container(),
  534. Provider.of<UserModule>(context).profile()['topMenu']['show'] != null && Provider.of<UserModule>(context).profile()['topMenu']['show'] == true ? separator() : Container(),
  535. Provider.of<UserModule>(context).profile()['specialOffer'] != null && Provider.of<UserModule>(context).profile()['specialOffer']['show'] == true ? Container(
  536. width: double.infinity,
  537. margin: EdgeInsets.only(top: 25),
  538. child: Column(
  539. crossAxisAlignment: CrossAxisAlignment.start,
  540. children: [
  541. Text(Provider.of<UserModule>(context).profile()['specialOffer']['label'][context.locale.toString()]??'Not Set', style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w600)),
  542. SizedBox(height: 12),
  543. Provider.of<ServiceModule>(context).specialOffer().isNotEmpty ? LayoutBuilder(
  544. builder: (context, constraints) {
  545. double size = (constraints.maxWidth/6)-13;
  546. double minWidth = 185;
  547. double minHeight = 250;
  548. return Wrap(
  549. spacing: 15, runSpacing: 15,
  550. children: List.generate(Provider.of<ServiceModule>(context).specialOffer().length, (i) => GestureDetector(
  551. child: ConstrainedBox(
  552. constraints: BoxConstraints(minWidth: minWidth, minHeight: minHeight),
  553. child: Container(
  554. width: size, height: size*1.4,
  555. child: Column(
  556. crossAxisAlignment: CrossAxisAlignment.start,
  557. children: [
  558. Expanded(child: imageTiles(imageUrl: Provider.of<ServiceModule>(context).specialOffer()[i]['_mobileImage'] ?? "null", width: double.infinity, height: double.infinity)),
  559. Container(
  560. height: ((size*1.4) > minHeight ? (size*1.4) : minHeight) / 2.3,
  561. padding: EdgeInsets.fromLTRB(6, 12, 6, 0),
  562. child: Column(
  563. crossAxisAlignment: CrossAxisAlignment.start,
  564. children: [
  565. Text(Provider.of<ServiceModule>(context).specialOffer()[i][U.langColumn(context, 'subject')], style: TextStyle(color: textColor, fontWeight: FontWeight.w600), maxLines: 2, overflow: TextOverflow.ellipsis),
  566. dashed(),
  567. Text(Provider.of<ServiceModule>(context).specialOffer()[i][U.langColumn(context, 'subjectDescription')], style: TextStyle(color: textColor, fontSize: 13), maxLines: 2, overflow: TextOverflow.ellipsis)
  568. ],
  569. ),
  570. )
  571. ],
  572. ),
  573. decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
  574. ),
  575. ),
  576. onTap: ()=>navigateTo(context, WebReqCreatePage(user: Provider.of<UserModule>(context, listen: false).user(), request: Provider.of<ServiceModule>(context, listen: false).specialOffer()[i])),
  577. )),
  578. );
  579. },
  580. ) : emptyWidget()
  581. ],
  582. ),
  583. ) : Container(),
  584. Provider.of<UserModule>(context).profile()['frequentlyRequested'] != null && Provider.of<UserModule>(context).profile()['frequentlyRequested']['show'] == true ? Container(
  585. width: double.infinity,
  586. margin: EdgeInsets.only(top: 36, bottom: 25),
  587. child: Column(
  588. crossAxisAlignment: CrossAxisAlignment.start,
  589. children: [
  590. Text(Provider.of<UserModule>(context).profile()['frequentlyRequested']['label'][context.locale.toString()]??'Not Set', style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w600)),
  591. SizedBox(height: 12),
  592. Provider.of<ServiceModule>(context).data().isNotEmpty ? LayoutBuilder(
  593. builder: (context, constraints) {
  594. double size = (constraints.maxWidth/6)-13;
  595. double minWidth = 185;
  596. double minHeight = 220;
  597. return Wrap(
  598. spacing: 15, runSpacing: 15,
  599. children: List.generate(Provider.of<ServiceModule>(context).data().length, (i){
  600. return GestureDetector(
  601. child: ConstrainedBox(
  602. constraints: BoxConstraints(minWidth: minWidth, minHeight: minHeight),
  603. child: Container(
  604. width: size, height: size*1.2,
  605. child: Column(
  606. crossAxisAlignment: CrossAxisAlignment.start,
  607. children: [
  608. Expanded(child: imageTiles(imageUrl: Provider.of<ServiceModule>(context).data()[i]['_mobileImage'] ?? "null", width: double.infinity, height: double.infinity)),
  609. Container(
  610. height: ((size*1.2) > minHeight ? (size*1.2) : minHeight) / 2.6,
  611. padding: EdgeInsets.symmetric(vertical: 12, horizontal: 6),
  612. child: Column(
  613. crossAxisAlignment: CrossAxisAlignment.start,
  614. children: [
  615. Expanded(child: Text(Provider.of<ServiceModule>(context).data()[i][U.langColumn(context, 'subject')], style: TextStyle(color: textColor, fontWeight: FontWeight.w600), maxLines: 2, overflow: TextOverflow.ellipsis)),
  616. Text(Provider.of<ServiceModule>(context).data()[i]['_frequentlyCount'].toString() + 'times'.tr(), style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis)
  617. ],
  618. ),
  619. )
  620. ],
  621. ),
  622. decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
  623. ),
  624. ),
  625. onTap: ()=>navigateTo(context, WebReqCreatePage(user: Provider.of<UserModule>(context, listen: false).user(), request: Provider.of<ServiceModule>(context, listen: false).data()[i])).then((val){
  626. val = val??true;
  627. if(val) homeFunc.getFrequentlyRequested(context);
  628. }),
  629. );
  630. }),
  631. );
  632. },
  633. ) : emptyWidget(),
  634. ],
  635. ),
  636. ):Container(),
  637. Provider.of<UserModule>(context).profile()['quickAction'] != null && Provider.of<UserModule>(context).profile()['quickAction']['show'] == true ? separator() : Container(),
  638. Provider.of<UserModule>(context).profile()['quickAction'] != null && Provider.of<UserModule>(context).profile()['quickAction']['show'] == true ? Container(
  639. width: double.infinity,
  640. margin: EdgeInsets.only(top: 25),
  641. child: Column(
  642. crossAxisAlignment: CrossAxisAlignment.start,
  643. children: [
  644. Text(Provider.of<UserModule>(context).profile()['quickAction']['label'][context.locale.toString()]??'Not Set', style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w600)),
  645. SizedBox(height: 12),
  646. Provider.of<ServiceModule>(context).quickAct().isNotEmpty ? LayoutBuilder(
  647. builder: (context, constraints) {
  648. var size = (constraints.maxWidth/2)-10;
  649. return Wrap(
  650. spacing: 20, runSpacing: 15,
  651. children: List.generate(Provider.of<ServiceModule>(context).quickAct().length, (i) {
  652. return GestureDetector(
  653. child: Container(
  654. width: size, child: Row(
  655. children: [
  656. imageTiles(imageUrl: Provider.of<ServiceModule>(context).quickAct()[i]['_mobileImage'] ?? "null", width: 110, height: 90),
  657. SizedBox(width: 20),
  658. Expanded(
  659. child: Column(
  660. crossAxisAlignment: CrossAxisAlignment.start,
  661. children: [
  662. Text(Provider.of<ServiceModule>(context).quickAct()[i][U.langColumn(context, 'subject')], style: TextStyle(color: textColor, fontWeight: FontWeight.w600), maxLines: 2, overflow: TextOverflow.ellipsis),
  663. dashed(),
  664. Text(Provider.of<ServiceModule>(context).quickAct()[i][U.langColumn(context, 'subjectDescription')], style: TextStyle(color: textColor), maxLines: 2, overflow: TextOverflow.ellipsis)
  665. ],
  666. ),
  667. ),
  668. Padding(padding: EdgeInsets.symmetric(horizontal: 20), child: U.iconsax('arrow-right-3', size: 16, color: textColor.withValues(alpha: 0.75)))
  669. ],
  670. ),
  671. decoration: BoxDecoration(
  672. color: Colors.white,
  673. border: Border.all(color: textColor.withValues(alpha: 0.15)),
  674. borderRadius: BorderRadius.all(Radius.circular(12))
  675. ),
  676. ),
  677. onTap: ()=>navigateTo(context, WebReqCreatePage(user: Provider.of<UserModule>(context, listen: false).user(), request: Provider.of<ServiceModule>(context, listen: false).quickAct()[i])),
  678. );
  679. }),
  680. );
  681. },
  682. ) : emptyWidget()
  683. ],
  684. ),
  685. ) : Container()
  686. ],
  687. ),
  688. ),
  689. ),
  690. ),
  691. )
  692. ],
  693. ),
  694. ) : Provider.of<UserModule>(context).resetData() ? RefreshPage(() {
  695. Provider.of<UserModule>(context).setResetData(false);
  696. homeFunc.getProfileData(context);
  697. }) : _timeLimit ? showButton(context) : loadingTemplate(() {if(mounted) setState(()=>_timeLimit=true);},);
  698. }
  699. Widget emptyWidget(){
  700. return Container(
  701. width: double.infinity, alignment: Alignment.center,
  702. margin: EdgeInsets.symmetric(vertical: 30),
  703. child: Text("notAvailable".tr(), style: TextStyle(color: textColor.withValues(alpha: 0.5), fontSize: 14, fontWeight: FontWeight.w400)),
  704. );
  705. }
  706. }
  707. // ---------------------------------------------------------------------------------------------------------------------------------------------
  708. class WebMenuEditorPage extends StatefulWidget {
  709. String scope;
  710. WebMenuEditorPage({required this.scope, super.key});
  711. @override
  712. State<WebMenuEditorPage> createState() => _WebMenuEditorPageState();
  713. }
  714. class _WebMenuEditorPageState extends State<WebMenuEditorPage> {
  715. List data = [];
  716. List available = [];
  717. @override
  718. void initState() {
  719. data.addAll(Provider.of<ServiceModule>(context, listen: false).topMenu()!);
  720. available.addAll(Provider.of<ServiceModule>(context, listen: false).reqGroup()!);
  721. super.initState();
  722. }
  723. @override
  724. Widget build(BuildContext context) {
  725. return Scaffold(
  726. backgroundColor: backgroundColor,
  727. appBar: PreferredSize(preferredSize: Size.fromHeight(0), child: AppBar(elevation: 0, backgroundColor: primaryColor)),
  728. body: Column(
  729. children: [
  730. Container(
  731. padding: EdgeInsets.symmetric(vertical: 25, horizontal: 100),
  732. child: Row(
  733. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  734. children: [
  735. Text('customTopMenu'.tr(), style: TextStyle(color: textColor, fontSize: 17, fontWeight: FontWeight.w500), overflow: TextOverflow.ellipsis),
  736. GestureDetector(
  737. child: Text('buttonBack'.tr(), style: TextStyle(color: primaryColor, fontSize: 14)),
  738. onTap: ()=>navigateBack(context),
  739. )
  740. ],
  741. ),
  742. ),
  743. divider(),
  744. Expanded(
  745. child: SingleChildScrollView(
  746. padding: EdgeInsets.symmetric(vertical: 25, horizontal: 100),
  747. child: Column(
  748. children: [
  749. Container(
  750. padding: EdgeInsets.symmetric(vertical: 20, horizontal: 30),
  751. decoration: BoxDecoration(color: Colors.white, border: Border.all(color: textColor.withValues(alpha: 0.15)), borderRadius: BorderRadius.all(Radius.circular(12))),
  752. child: IntrinsicHeight(
  753. child: Row(
  754. crossAxisAlignment: CrossAxisAlignment.stretch,
  755. children: [
  756. Expanded(
  757. child: Column(
  758. crossAxisAlignment: CrossAxisAlignment.start,
  759. children: [
  760. DragAndDropLists(
  761. disableScrolling: true,
  762. lastItemTargetHeight: 8,
  763. lastListTargetSize: 0,
  764. children: [
  765. DragAndDropList(
  766. contentsWhenEmpty: Padding(
  767. padding: const EdgeInsets.only(top: 16.0, bottom: 16.0),
  768. child: Text("emptyMenuAlert".tr(), style: TextStyle(fontStyle: FontStyle.italic, color: primaryColor.withValues(alpha: 0.60)),),
  769. ),
  770. canDrag: false,
  771. children: List<DragAndDropItem>.generate(data.length, (i){
  772. return DragAndDropItem(
  773. child: Container(
  774. padding: EdgeInsets.symmetric(vertical: 8),
  775. child: Row(
  776. children: [
  777. imageContainer(data[i]['iconUrl']),
  778. SizedBox(width: 12),
  779. Expanded(
  780. child: Column(
  781. crossAxisAlignment: CrossAxisAlignment.start,
  782. children: [
  783. Text(data[i][U.langColumn(context, 'description')], style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
  784. SizedBox(height: 4),
  785. Text(data[i][U.langColumn(context, 'description')], style: TextStyle(color: textColor, fontSize: 12, fontWeight: FontWeight.w300), overflow: TextOverflow.ellipsis),
  786. ],
  787. ),
  788. ),
  789. GestureDetector(
  790. child: U.iconsax('bold/minus-cirlce', color: Color(0xffD81010)),
  791. onTap: (){
  792. setState(() {
  793. available.add(data[i]);
  794. data.remove(data[i]);
  795. });
  796. },
  797. ),
  798. SizedBox(width: 40)
  799. ],
  800. ),
  801. ),
  802. );
  803. }),
  804. )
  805. ],
  806. onItemReorder: (int oldItemIndex, int oldListIndex, int newItemIndex, int newListIndex) {
  807. setState(() {
  808. var movedItem = data.removeAt(oldItemIndex);
  809. data.insert(newItemIndex, movedItem);
  810. });
  811. },
  812. onListReorder: (int oldListIndex, int newListIndex) {},
  813. itemDragHandle: DragHandle(
  814. child: Icon(Icons.menu_rounded, color: textColor),
  815. ),
  816. ),
  817. SizedBox(height: 20),
  818. Text('*${'limitTopMenu'.tr()}', style: TextStyle(color: textColor))
  819. ],
  820. ),
  821. ),
  822. Container(
  823. width: 1, height: double.infinity,
  824. color: textColor.withValues(alpha: 0.15),
  825. margin: EdgeInsets.symmetric(horizontal: 30),
  826. ),
  827. Expanded(
  828. child: Column(
  829. children: List.generate(available.length, (i){
  830. return Container(
  831. padding: EdgeInsets.symmetric(vertical: 8),
  832. child: Row(
  833. children: [
  834. imageContainer(available[i]['iconUrl']),
  835. SizedBox(width: 12),
  836. Expanded(
  837. child: Column(
  838. crossAxisAlignment: CrossAxisAlignment.start,
  839. children: [
  840. Text(available[i][U.langColumn(context, 'description')], style: TextStyle(color: textColor, fontSize: 14), overflow: TextOverflow.ellipsis),
  841. SizedBox(height: 4),
  842. Text(available[i][U.langColumn(context, 'description')], style: TextStyle(color: textColor, fontSize: 12, fontWeight: FontWeight.w300), overflow: TextOverflow.ellipsis),
  843. ],
  844. ),
  845. ),
  846. GestureDetector(
  847. child: U.iconsax('bold/add-circle', color: Color(0xffD81010)),
  848. onTap: (){
  849. if(data.length < 7){
  850. setState(() {
  851. data.add(available[i]);
  852. available.remove(available[i]);
  853. });
  854. }
  855. else{
  856. showError(context, 'maxMenu'.tr());
  857. }
  858. },
  859. ),
  860. ],
  861. ),
  862. );
  863. }),
  864. ),
  865. )
  866. ],
  867. ),
  868. ),
  869. ),
  870. SizedBox(height: 20),
  871. Row(
  872. mainAxisAlignment: MainAxisAlignment.start,
  873. children: [
  874. buttonTemplate(text: 'textCancel'.tr(), backgroundColor: Colors.black12, borderColor: Colors.black12, textColor: textColor, width: 120, height: 40, action: (){
  875. navigateBack(context);
  876. }),
  877. SizedBox(width: 20),
  878. buttonTemplate(text: 'done'.tr(), backgroundColor: primaryColor, borderColor: primaryColor, width: 120, height: 40, action: ()async{
  879. if(data.isNotEmpty){
  880. List codes = [];
  881. data.forEach((element) {
  882. codes.add(element['code']);
  883. });
  884. var res = await ApiAuthProvider().postData('/api/informants/topMenu/${widget.scope}', {'topMenu': codes.join(';')}, null, context);
  885. if(res != null){
  886. Provider.of<ServiceModule>(context, listen: false).setTopMenu(data);
  887. Provider.of<ServiceModule>(context, listen: false).setReqGroup(available);
  888. navigateBack(context, exc: true);
  889. }
  890. } else if(available.isEmpty) {
  891. navigateBack(context);
  892. } else {
  893. showError(context, "selectAlert".tr());
  894. }
  895. })
  896. ],
  897. )
  898. ],
  899. ),
  900. ),
  901. )
  902. ],
  903. ),
  904. );
  905. }
  906. imageContainer(iconUrl){
  907. return Container(
  908. padding: EdgeInsets.all(5),
  909. child: Image(image: CachedNetworkImageProvider(iconUrl+'?bridge-cache=true', cacheManager: CacheManager(CacheMan.config(iconUrl+'?bridge-cache=true'))), width: 50, height: 50),
  910. decoration: BoxDecoration(
  911. color: Colors.white,
  912. borderRadius: BorderRadius.all(Radius.circular(12)),
  913. border: Border.all(width: 0.2, color: Colors.black12),
  914. boxShadow: [BoxShadow(color: Colors.grey.withValues(alpha: 0.3), blurRadius: 2, offset: Offset(0, 2))]
  915. ),
  916. );
  917. }
  918. }